var textData = {
    text: "您好中国！广州力麒",
    "content": "联办事项",
                       
                        "x": 0,
                        "y": 0,
                        "width": 144,
                        "height": 32,
                        "borderSize": 1,
                        "showBorder": true,
                        "selected": false,
                        "rowspan": 1,
                        "colspan": 0,
                        "parentRow": -1,
                        "parentCol": -1,
                        "mWidth": 144,
                        "mHeight": 64,
                        "textAlign": 0,
                        "hasCheckBox": false,
                        "checkStatus": false,
                        "borderStyle": "solid",
                        "borderWidth": "1px",
                        "borderColor": "black",
                        "verticalAlign": "top",
                        "indent": 0,
    fontStyles: [
                { start: 0, end: 2, font: "黑体"},
                { start: 2, end: 6, font: "楷体"}
            ],
    fontSize: [
                { start: 0, end: 8, font: "黑体", fontSize:200 },
                { start: 8, end: 16, font: "楷体", fontSize:200}
            ],           
    underlineColor: [
                { start: 0, end: 6,color: "red" },
                { start: 6, end: 16,color: "green" }
            ], 
    fontColor: [
                { start: 0, end: 2,color: "red" },
                { start: 2, end: 6,color: "green" }
            ],                     
    italic: [ //斜体属性
        { start: 0, end: 4, italic: true }
            ],
    bold: [ // 加粗
        { start: 3, end: 5, bold: true }
            ],
    underline: [ // 下划线
        { start: 0, end: 16, underline: true }
            ],
    underlineStyle:[ // 下划线
        { start: 0, end: 3, style: 'wavy' }
            ],
    lineThrough: [ // 删除线
        { start: 4, end: 6, lineThrough: true }
            ],
    background: [ // 背景色
        { start: 5, end: 17, background: 'rgba(255, 255, 0, 0.5)' }
            ],
    styles: [ ],
    firstLineIndent: 0,
    lineSpacing: 15, // 行间距
    horizontalAlign: 'left', //水平对齐方式
    verticalAlign: 'top', // 垂直对齐方式
    cells_selectionStart:0, // 选区开始位置
    cells_selectSecond:0, // 选区第二个位置
    cells_selectionEnd:0, //自动选区结束
    maxHeight:16,
    minHeight:16,
    cursorVisible:false
};
let hadMyTestButton=false;
let cells_isSelecting = false;
// let cells_selectionStart = null;
// let cells_selectionEnd = null;
const cells_charWidths = [];
let cells_lineHeight = 0;        	// 添加行高变量
let cells_cursorPosition = {index:-1,x:0,y:0,font:"宋体",fontSize:16}; // 光标位置         

let hasSelection = false;  			// 添加一个变量来跟踪选择状态
let isComposing = false;
let linesData = []; 				// 用于存储处理后的行数据

let isDragging = false; 			// 跟踪是否正在拖拽（即选择文本）
let dragStartIndex = -1; 			// 拖拽开始时的字符索引
let isLeftButtonMouseDown=false;   	//光标左键按下

const editableDiv = document.getElementById('editableDiv');
let initialText = "";      		// 记录开始输入时的文本
let initialSelectionStart = 0; 	// 记录开始输入时的光标或选区开始位置
let initialSelectionEnd = 0;   	// 记录开始输入时的光标或选区结束位置
let initialTextLength = 0;
let initialCursorPosition = 0;
let hadGen = 0;

editableDiv.style.width = '1px';
editableDiv.style.height = '1px';
editableDiv.style.opacity = 0;
let  cellsCtx=null;
let  cellsCanvas=null;
let  headerDiv=null;
var editer_locked_selectChars={start:0,end:0};    //用于锁定当前编辑器时的选中的字符串描术
let textArea_offsetX=12;
let textArea_offsetY=3;




var totalCellHeight=0;    	//totalCellHeight声明为单元格的总高度，是所有文本行高的累计。当文本输入时或自适应调整画布的高。2024 4-24  
var extHeightFlag=false;  	//当文本行高超过单元格里行高时，设置为true，表示需要扩展画布的高度。
var lastMessage=0;        	//用于记录上一次的文本信息，用于判断是否需要重新生成文本。
var messageType=0;        	//0在渲染过程中发的消息，1在文字输入时的消息
var segmentHeight=0;      	//最大可容切割高度, 当前页面剩余的容量.
var hasToCutCells=false;   	//必要时监测切割
var tempSegmentPosition=0; 	//临时切割位置记录
var lastSegmentPosition=0; 	//最终的切割位置记录
var maxTextHeight=0;       	//用于记录文本的最大高度，用于自适应调整画布的高度。
var current_columns_index=0;//单元格的列索引
var lastCellsTotalOfHeight=0;//当前表格所有单元格高
var current_tables_canvas_drawing_position_y=0;//当前临时画板上的参考坐标,用于循环绘制单元格中累计已输出文字的Y坐标
var current_cell_height=0;   //当前单元格高
var cells_Source_Height=0;   //临时绘制单元格有效高度累计,是文字一行输出后的Y轴的坐标，每输出 一行就要将当前字体大小加行间距一起算进来.
var cells_Dist_action=0;//1表示页尾不足，写完要跳转一新页
var upstairs_cells_height=0; //上一楼的单元格总高
var upstairs_text_lineHeight=0;//上一楼的文本行高
var b_c_global_position_y=0 ;  //循环表格行与列，与Cells绘制共享Y坐标 
var where_to_call="";
var cellsCompareData=[
    {
        textHeight:0,    //实际文本高
        segmentHeight:0, //切割高度
        cellsHeight:0,   //单元格高度
        columnsIndex:-1  //列数

    }
];
var pageGlobalYPosition=0;     //记当表格或自然段在绘制过程中与页面编号的对应关系
var scan_Global_RowOfTable=0;  //扫描每行单元格,由drawCellOfTable传递给CellEdit
var single_table_cell_index=0; //在绘制表格过程判断当前行有可能出现跨页的情况，需要记录当前行的单元格的索引,标识当前哪一列正在绘制
                               //当整行绘制完成后，会将这几列的真实高度作为参考比较.哪列触发了切口文字完整性计算
var current_cell_position_y=0
var inMeasure=false;
var segment_Info_part=[];  
var segment_Info=[];           //定义切割信息数组,当一个表格跨越多个页面时,表可能要出现多个切口,这里要记录切口的位置信息。主要是避免文字被切开
// var newSegment1 = {
//     segment_index: 0,
//     sliceType:0,
//     offset_X: 10,
//     offset_Y: 20,
//     width: 700,
//     height: 900
// };
    //setInterval(blinkCursor, 500); // 设置光标闪烁的间隔
var hasNoEnoughSpacing=false; //没有足够的空间容纳单元格首行文本
var moveToNextPage=false;     //当hasNoEnoughSpacing=true时，有可能要整表后移一页。前提是当前页小于或等于新页面的高。
var offsetHeaderLine=0;       //当hasNoEnoughSpacing=true时，有可能要整表后移一页。这时不足的空间要计算出来，给到表格下移后增加头部偏移。
var offsetLastSegment=0;      //偏移页面的剩余空间高度
var showParaInCellEdit=false; //当前显示单个段落内容.
var debugSN="未知";           //用于显示/编辑对像的标识ID，为了更好的识别当前的对像是谁.
var spacingDeviation=0 ;      //自然段跨页空间补偿
var inMeasureAction=0  ;      //0纯绘图；1 切片
var totalParaSegmentHeight=0; //统计当前自然段的高度
var first_line_text_height=0; //first_line_text_height 当第一页不能容下表格时，要计算首行能不能放在这个页面，确保完整不被切部分
var first_line_text="";       //上半行末尾行内容
var cells_source_offset_rest_page=0;//3.1.2.1.1计算出剩下容量，作为偏移; 即记录上一次最大的首行单元格文字行可容的位置 
var cells_Dist_Start_Y=0;     //将源表格画板内容复制到目标页面上的开始坐标Y

//5-23切割要记录的内容：
//1.形成当前的切块，包括两部分数据，1是拷贝源 的起始与高度；2是目标源的起始坐标与高度；
//2.记录最后一次拷贝源, 目标源 分别的结束位置。将做来下一次分块的起点位置.
//3. 由于两都高度是一样的，只需要一个source_copy_block_height来表示即可。
//3. 由于两都高度是一样的，只需要一个source_copy_block_height来表示即可。
//4. 保存最后一个单元格高度
//5. 在一页中，经常是有多行单元格累加后才能占满一页，在逐行比较是不容得下当前列的比较，如果可以就要累计一下这些单元格行高。变量：dist_total_cells_height
//重新定义 这个坐标为全局绝对坐标，包括页面偏移： 
var source_copy_start_position_y=0;
var source_copy_block_height=0;
var dist_copy_start_position_y=0;
var dist_copy_cell_height=0;
var dist_total_cells_height=0;
//页面与表格单元格绘制规则模型
//***************************************************/
var Hp=985; //页面高度
var Hct=0;  //下半页单元格累计高度  Hct<=Hp
var Hc=0 ;  //当前单元格高度
var Hs=0 ;  //上半截单元格高度（当一页容不下一行单元格时）
var Ha=0 ;  //Ha=Hc-Hs
var Has=0;  //下半截页面可用高度 Hp-Hct
//***************************************************/
// 函数用于比较两个对象是否相等
function isEquivalent(a, b) {
    // 获取对象属性的名称
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // 如果属性数量不同，那么对象不等
    if (aProps.length != bProps.length) {
        return false;
    }

    // 检查每个属性的值是否相等
    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];
        if (a[propName] !== b[propName]) {
            return false;
        }
    }

    // 如果所有属性都相等，那么对象等
    return true;
}

// 检查函数
function checkDuplicateAndInsert(segmentArray, newSegment) {
    // 检查数组中是否存在一个对象在所有属性上都与 newSegment 相匹配
    var exists = segmentArray.some(function(segment) {
        return isEquivalent(segment, newSegment);
    });
    
    // 如果不存在，则插入新段落
    if (!exists) {
        segmentArray.push(newSegment);
        ///console.log("新段落已插入:");
       // console.log(newSegment);
       return false;
    } else {
      //  console.log("存在重复的段落，未插入新数据。");
    }
    return true;
}
function getCurrentTime() {
    // 获取当前系统时间
    const currentTime = new Date();
    
    // 获取年、月、日、小时和分钟
    const year = currentTime.getFullYear();
    const month = currentTime.getMonth() + 1; // 月份从0开始，需要加1
    const day = currentTime.getDate();
    const hours = currentTime.getHours();
    const minutes = currentTime.getMinutes();

    // 格式化月份和日期为两位数
    const formattedMonth = month < 10 ? `0${month}` : month;
    const formattedDay = day < 10 ? `0${day}` : day;

    // 格式化时间为"YYYY-M-D HH:MM"格式
    const formattedTime = `${year}-${formattedMonth}-${formattedDay} ${hours}:${minutes}`;

    // 返回格式化后的时间
    return formattedTime;
}

document.addEventListener("DOMContentLoaded", function() {
       

	isLeftButtonMouseDown=false;

            // 动态加载header.html
    if(hadMyTestButton==true)
    {

        fetch('/cellsEditButtons.html')
        .then(response => response.text())
        .then(html => {
            headerDiv = document.getElementById('cellsEditButtons');
            headerDiv.innerHTML = html;
    
            // 在内容加载后添加事件
            // 为父容器添加事件监听器
            const CellsEditButtons = document.getElementById('cellsEditButtons');
            CellsEditButtons.addEventListener('click', handleCellsEditButtonsClick);
        })
        .catch(error => {
           // console.error('Error loading header:', error);
        });

    }

         cellsCanvas = document.getElementById('cellsCanvas');
         cellsCtx = cellsCanvas.getContext('2d');
    	 cellsCanvas.addEventListener('contextmenu', (e) => {
            e.preventDefault(); // 阻止默认的右键菜单

            const rect = cellsCanvas.getBoundingClientRect(); // 获取cellsCanvas的边界
            const menuWidth = CellsEditMenu.offsetWidth;
            const menuHeight = CellsEditMenu.offsetHeight;

            // 计算菜单的最佳位置，确保它不会超出cellsCanvas边界
            let x = e.clientX - rect.left; // 转换为相对于cellsCanvas的位置
            let y = e.clientY - rect.top;

            console.log(x, y);
            // 如果菜单超出右侧
            if (x + menuWidth > cellsCanvas.width) {
                x = cellsCanvas.width - menuWidth;
            }
            // 如果菜单超出底部
            if (y + menuHeight > cellsCanvas.height) {
                y = cellsCanvas.height - menuHeight;
            }

            // 设置自定义菜单的位置并显示
            CellsEditMenu.style.top = `${y}px`;
            CellsEditMenu.style.left = `${x}px`;
            CellsEditMenu.style.display = 'block';
        });


        

    function insertTextAtCursor(text) {
        // 粘贴时的文本插入逻辑
        const beforeCursor = textData.text.slice(0, cells_cursorPosition);
        const afterCursor = textData.text.slice(cells_cursorPosition);
        textData.text = beforeCursor + text + afterCursor;
        cells_cursorPosition += text.length;  // 更新光标位置
        // 需要更新样式信息（省略）
    }



    cellsCanvas.addEventListener('click', function() {
        editableDiv.focus(); // 当画布被点击时，设置焦点到editableDiv
    	});

        // 根据需要添加更多事件监听器，如compositionstart, compositionupdate

        // 开始输入复合字符（如中文字符）
        editableDiv.addEventListener('compositionstart', function(e) {
            isComposing = true;
            //console.log('QQ3 开始输入  =================================');
            initialText = textData.text;
            initialSelectionStart = textData.cells_selectionStart; // 假设你已经有这些值
            initialSelectionEnd = textData.cells_selectionEnd;
                        
        
        });

        // 输入复合字符过程中（可选，如果你需要实时获取输入法中的文本，可以使用此事件）
    editableDiv.addEventListener('compositionupdate', function(e) {
            // e.data 包含当前输入法组合中的文本
            //console.log('QQ3 输入更新  	:', e.data);
           
            clearSelection();
        });


    editableDiv.addEventListener('compositionend', function(e) {
            //console.log(e.data); // 打印输入的文字
            // 更新cellsCanvas的文本内容
            isComposing = false;
                // // e.data 包含完成输入的复合字符
                // // 在这里插入字符到文本中
                const beforeCursor = textData.text.slice(0, textData.cells_selectionStart);
                const afterCursor = textData.text.slice(textData.cells_selectionStart);
                textData.text = beforeCursor + e.data + afterCursor;
                updateStylesForInsert(textData.cells_selectionStart,e.data.length);
                cells_cursorPosition += e.data.length; // 更新光标位置，这里假设插入文本的长度就是e.data的长度
                //console.log('QQ3 输入完成	:', e.data," 字符串长",e.data.length);

               
                textData.cells_selectionStart+=e.data.length;
                textData.cells_selectionEnd = textData.cells_selectionStart;
            
                textData.cursorVisible = true; // 可选：同时隐藏光标             
                hadGen=false;
                renderText(); // 重新渲染文本和样式
        });

        // 确保editableDiv可以接收输入
       
    editableDiv.addEventListener('paste', function(e) {
       
            e.preventDefault(); // 阻止默认粘贴行为

            // 获取剪贴板中的文本内容

            const pasteText = e.clipboardData.getData('text');
			//console.log('QQ3 粘贴文本     :', pasteText);
            // 假定cells_cursorPosition是当前光标在textData.text中的位置
            if (cells_cursorPosition === null) {
                cells_cursorPosition = textData.text.length; // 如果没有指定光标位置，则默认为文本末尾
            }

            // 将文本插入到光标位置
            const beforeCursor = textData.text.slice(0, cells_cursorPosition);
            const afterCursor = textData.text.slice(cells_cursorPosition);
            textData.text = beforeCursor + pasteText + afterCursor;

          

            // 更新样式（这个示例没有改变样式，但你可能需要根据插入的文本更新样式）
            updateStylesForInsert(cells_cursorPosition, pasteText.length);

              // 更新光标位置
              cells_cursorPosition += pasteText.length;
              hadGen=false;

            // 重新渲染文本
            renderText();
        });

    function copyToClipboard() {

        if (textData.cells_selectionStart === null || textData.cells_selectionEnd === null || textData.cells_selectionStart === textData.cells_selectionEnd) {
            //console.log("没有选中的文本可以复制");
            return;
        }

        // 提取选中的文本
        const selectedText = textData.text.slice(textData.cells_selectionStart, textData.cells_selectionEnd);

        // 创建一个临时的textarea元素用于复制操作
        const textarea = document.createElement('textarea');
        textarea.value = selectedText;
        document.body.appendChild(textarea);

        // 选中文本并复制
        textarea.select();
        document.execCommand('copy');

        // 移除临时创建的textarea
        document.body.removeChild(textarea);
        hadGen=false;
        renderText();

        //console.log("已复制到剪贴板: " + selectedText);
    }



   

    function insertTextAtPosition(text, position) {
        // 插入文本并更新textData.text
        const beforeText = textData.text.substring(0, position);
        const afterText = textData.text.substring(position);
        textData.text = beforeText + text + afterText;

        // 更新样式范围
        updateStylesForInsert(position, text.length);
        hadGen=false;
        // 重新渲染文本（这取决于你的渲染逻辑）
        renderText();
    }


    function isInSelection(x, y) {
    // 首先，确定y坐标所在的行
    let accumulatedHeight = 50; // 初始行高，根据实际情况调整
    let globalCharIndex = 0; // 全局字符索引

    for (let line of linesData) {
        if (y >= accumulatedHeight && y < accumulatedHeight + line.height) {
            // 现在，我们找到了y坐标所在的行，接下来确定x坐标是否在选区内
            if (globalCharIndex + line.text.length < textData.cells_selectionStart || globalCharIndex > textData.cells_selectionEnd) {
                // 如果整行都在选区之外
                return false;
            }

            // 计算行内的选区开始和结束位置
            const lineSelectionStart = Math.max(textData.cells_selectionStart - globalCharIndex, 0);
            const lineSelectionEnd = Math.min(textData.cells_selectionEnd - globalCharIndex, line.text.length);

            // 累加当前行字符的宽度，以确定选区的x坐标范围
            let cursorX = 0;
            for (let i = 0; i < line.text.length; i++) {
                if (i >= lineSelectionStart && i < lineSelectionEnd) {
                    // 如果在选区范围内，检查x坐标是否落在当前字符的宽度范围内
                    const char = line.text[i];
                    const charStyle = line.styles.find(s => i >= s.start && i < s.end) || { fontSize: 16, font: "Arial", color: "black" };
                    cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
                    const metrics = cellsCtx.measureText(char);
                    const charWidth = metrics.width;

                    if (x >= cursorX && x < cursorX + charWidth) {
                        // 如果x坐标在当前字符的宽度范围内，则说明光标在选区内
                        return true;
                    }
                }
                // 更新cursorX以反映当前行内的位置
                cursorX += cellsCtx.measureText(line.text[i]).width;
            }

            // 如果循环结束还没有找到匹配，说明点击位置不在选区内
            return false;
        }
        accumulatedHeight += line.height; // 更新累加的行高
        globalCharIndex += line.text.length; // 更新全局字符索引
    }

    // 如果循环结束还没有找到匹配的行，说明点击位置不在任何选区内
    return false;
}




    function updateCurrentLineStyles(currentLineStyles, charStyle, relativeIndex) {
        let styleExists = currentLineStyles.some(style => {
            return style.font === charStyle.font &&
                style.fontSize === charStyle.fontSize &&
                style.color === charStyle.color &&
                style.underline === charStyle.underline &&
                style.underlineStyle === charStyle.style &&
                style.underlineColor === charStyle.color &&
                style.end === relativeIndex
        });

        if (!styleExists) {
            currentLineStyles.push({ ...charStyle, start: relativeIndex, end: relativeIndex + 1 });
        } else {
            currentLineStyles[currentLineStyles.length - 1].end = relativeIndex + 1;
        }
    }



    cellsCanvas.addEventListener('mousedown', function(e) {
       
      

        // cellsCanvas = document.getElementById('cellsCanvas');
        // cellsCtx = cellsCanvas.getContext('2d');

        const rect = cellsCanvas.getBoundingClientRect();
        var x = e.clientX - rect.left;
        var y = e.clientY - rect.top;
        //console.log("C1 鼠标按下x:",x," y:",y);
        var   cellCanvasOffset = $('#cellsCanvas').offset();       
        // x = x-cellcanvasOffset.left;
        // y = y- cellcanvasOffset.top;
       // console.log("C1 鼠标按下x:",x," y:",y);
      
        if (e.button === 0) { // 0 表示鼠标左键
            isLeftButtonMouseDown = true;
           
           // console.log(`QQ2 Mouse down at (${x}, ${y})`);
        }
      
        let cell_start_x = cellCanvasOffset.left;
        let cell_start_y = cellCanvasOffset.top;

       // console.log("My canvas offset x:",x," y:",y," cell_start_x:",cell_start_x," cell_start_y:",cell_start_y);


        if (e.button === 2) { // 检查是否为右键点击
            // 如果是在选区内点击右键，保持选区状态
            if (isInSelection(x, y)) {
                // 可以在这里触发其他与右键相关的行为，例如显示上下文菜单
                return; // 不清除选区也不开始新的选择
            }
            // 对于右键点击，如果不在选区内，也可以选择不处理
            return;
        }





        const charIndex = getCharIndex(x, y); // 通过 x, y 坐标获取字符索引
       // console.log("QQ2: My canvas offset x:",x," y:",y," cell_start_x:",cell_start_x," cell_start_y:",cell_start_y," charIndex:",charIndex);
        var   myCharInfo=getCharMoreInfo(x, y);
        //console.log("QQ: -----------------> char:",myCharInfo.content," charIndex:",myCharInfo.index," x:",myCharInfo.x," y:",myCharInfo.y," fontSize:",myCharInfo.fontSize," font:",myCharInfo.font);
        if (charIndex !== -1) {
            isDragging = true;
            textData.cursorVisible = true; // 可选：同时隐藏光标
            dragStartIndex = charIndex;
            textData.cells_selectionStart = charIndex;
            textData.cells_selectionEnd = charIndex ; //charIndex+1 开始时选中一个字符

           
         
            //cells_cursorPosition = getCharPosition(x, y); // 更新光标位置
            cells_cursorPosition.x = myCharInfo.x; 
            cells_cursorPosition.y = myCharInfo.y;
            cells_cursorPosition.index = myCharInfo.index;
            cells_cursorPosition.fontSize = myCharInfo.fontSize;
            cells_cursorPosition.font = myCharInfo.font;

            //console.log("QQ3: My Position index:",cells_cursorPosition.index," start:",textData.cells_selectionStart," end:",textData.cells_selectionEnd," x:",cells_cursorPosition.x," y:",cells_cursorPosition.y," fontSize:",cells_cursorPosition.fontSize," font:",cells_cursorPosition.font);
            cells_isSelecting = true;
            //updateCursorPosition(e.clientX);
        }
        else{
            console.log(" QQ3: 未找到字符");
             textData.cursorVisible = true; // 可选：同时隐藏光标
            dragStartIndex = charIndex;
            textData.cells_selectionStart = charIndex;
            textData.cells_selectionEnd = charIndex ; //charIndex+1 开始时选中一个字符

        }
        renderText(); // 重新渲染文本以更新画布状态
    });

    //通过坐标返回当前光标位置下的文字,和他们的相关字体大小,高底,颜色,等属性,用于加工显示光标.index,x,y,fontSize,font,content
    function getCharMoreInfo(x, y) {
        let accumulatedHeight = 0; // 用于累加行高，以确定点击位置的y坐标
         let  lineSpacing=15;
         let charStyle=[];
         let currentChar='';
         let cursorX = 0; // 累加当前行字符的宽度，以确定点击位置的x坐标
        // 遍历每一行文本
        for (let lineIndex = 0; lineIndex < linesData.length; lineIndex++) {
            const line = linesData[lineIndex]; //取出一行数据，，同时计算生成Y 坐标用于比对
           
            //console.log("C3 lineStr: " + line.text);
            if (y >= accumulatedHeight && y < accumulatedHeight + line.height) {
                // 确定鼠标点击在当前行内
                cursorX = 0;//累加当前行字符的宽度，以确定点击位置的x坐标
               
                let accumulatedLength = linesData.slice(0, lineIndex).reduce((acc, cur) => acc + cur.text.length, 0); // 累加之前所有行的字符长度，以确定全局字符索引

                for (let i = 0; i < line.text.length; i++) {
                    currentChar = line.text[i];
                    // 查找该字符的样式
                    //console.log("C3 按字符查样：： ",char);
                    charStyle = line.styles.find(s => i >= s.start && i < s.end) || { fontSize: 16, font: "Arial", color: "black" };
                    cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
                    const metrics = cellsCtx.measureText(currentChar);
                    const charWidth = metrics.width;

                    if (x >= cursorX && x < cursorX + charWidth) {
                        // 如果点击位置在当前字符的宽度范围内，则返回这个字符的全局索引
                        return {index:accumulatedLength + i,x:cursorX ,y:accumulatedHeight,fontSize:`${charStyle.fontSize}`,font:`${charStyle.font}`,content:currentChar};
                    }

                    cursorX += charWidth; // 更新累加的宽度，以反映当前行内的位置
                }
                // 如果x坐标超出了当前行的最后一个字符，但y坐标仍在当前行内，则视为点击了该行的最后一个字符
                return {index:accumulatedLength + line.text.length - 1,x:cursorX,y:accumulatedHeight,fontSize:`${charStyle.fontSize}`,font:`${charStyle.font}`,content:`${currentChar}`}; 
            }
            accumulatedHeight += line.height+lineSpacing; // 更新累加的行高，以反映不同行的位置
        }

        return -1; // 如果没有找到对应的字符，返回-1
    }



            function getCharIndex(x, y) {
                let accumulatedHeight = 0; // 用于累加行高，以确定点击位置的y坐标
 				let  lineSpacing=textData.lineSpacing;
                // 遍历每一行文本,从第0行开始
                for (let lineIndex = 0; lineIndex < linesData.length; lineIndex++) {
                    const line = linesData[lineIndex]; //取出一行数据，，同时计算生成Y 坐标用于比对
                   
                    //console.log("C3 lineStr: " + line.text);
                    if (y >= accumulatedHeight && y < accumulatedHeight + line.height) {
                        // 确定鼠标点击在当前行内
                        let cursorX = 0; // 累加当前行字符的宽度，以确定点击位置的x坐标
                        let accumulatedLength = linesData.slice(0, lineIndex).reduce((acc, cur) => acc + cur.text.length, 0); // 累加之前所有行的字符长度，以确定全局字符索引

                        for (let i = 0; i < line.text.length; i++) {
                            const char = line.text[i];
                            // 查找该字符的样式
                            //console.log("QQ2: 按字符查样：： ",char);
                            const charStyle = line.styles.find(s => i >= s.start && i < s.end) || { fontSize: 16, font: "Arial", color: "black" };
                            cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
                            const metrics = cellsCtx.measureText(char);
                            const charWidth = metrics.width;

                            if (x >= cursorX && x < cursorX + charWidth) {
                                // 如果点击位置在当前字符的宽度范围内，则返回这个字符的全局索引
                                return accumulatedLength + i;
                            }

                            cursorX += charWidth; // 更新累加的宽度，以反映当前行内的位置
                        }
                        // 如果x坐标超出了当前行的最后一个字符，但y坐标仍在当前行内，则视为点击了该行的最后一个字符
                        return accumulatedLength + line.text.length - 1;
                    }
                    accumulatedHeight += line.height+lineSpacing; // 更新累加的行高，以反映不同行的位置
                }

                return -1; // 如果没有找到对应的字符，返回-1
            }

            //重原来返回下标索引 改为X,Y坐标

            function getCharPosition(x, y) {
                let accumulatedHeight = 0; // 用于累加行高，以确定点击位置的y坐标

                for (let lineIndex = 0; lineIndex < linesData.length; lineIndex++) {
                    const line = linesData[lineIndex];
                    //console.log("C3 lineStr: " + line.text);
                    if (y >= accumulatedHeight && y < accumulatedHeight + line.height) {
                        // 确定鼠标点击在当前行内
                        let cursorX = 0; // 累加当前行字符的宽度，以确定点击位置的x坐标
                        let accumulatedLength = linesData.slice(0, lineIndex).reduce((acc, cur) => acc + cur.text.length, 0); // 累加之前所有行的字符长度，以确定全局字符索引

                        for (let i = 0; i < line.text.length; i++) {
                            const char = line.text[i];
                            // 查找该字符的样式
                           // console.log("C3 按字符查样：： ",char);
                            const charStyle = line.styles.find(s => i >= s.start && i < s.end) || { fontSize: 16, font: "Arial", color: "black" };
                            cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
                            const metrics = cellsCtx.measureText(char);
                            const charWidth = metrics.width;

                            if (x >= cursorX && x < cursorX + charWidth) {
                                // 如果点击位置在当前字符的宽度范围内，则返回这个字符的全局索引
                                return {x:cursorX,y:accumulatedHeight};
                            }

                            cursorX += charWidth; // 更新累加的宽度，以反映当前行内的位置
                        }
                        // 如果x坐标超出了当前行的最后一个字符，但y坐标仍在当前行内，则视为点击了该行的最后一个字符
                        return  {x:cursorX,y:accumulatedHeight};;
                    }
                    accumulatedHeight += line.height; // 更新累加的行高，以反映不同行的位置
                }

                return -1; // 如果没有找到对应的字符，返回-1
            }




        let lastSelectionEnd = null; // 全局变量，记录上次选择结束的位置


        cellsCanvas.addEventListener('mousemove', function(e) {

            cellsCanvas = document.getElementById('cellsCanvas');
            cellsCtx = cellsCanvas.getContext('2d');
     
           // console.log("QQ4 mousemove:",isDragging);
            if (!isDragging) return; // 如果没有在拖拽，就不执行任何操作

            const rect = cellsCanvas.getBoundingClientRect();
            var x = e.clientX - rect.left;
            var y = e.clientY - rect.top;

     

            const charIndex = getCharIndex(x, y);

            if (charIndex !== -1) {
                //dragStartIndex为最近一次点击的位置。
                if (charIndex < dragStartIndex) {
                    textData.cells_selectionStart = charIndex;                    
                    textData.cells_selectionEnd = dragStartIndex ; // 从右向左选择

                   // console.log("QQ4 charIndex < dragStartIndex",charIndex);
                    
                } else {


                    textData.cells_selectionStart = dragStartIndex;

                   
                    textData.cells_selectSecond =charIndex;//真实记录第二个选择位置
                    if(dragStartIndex!==charIndex)
                    {
                        //console.log("QQ4 单元格选择 dragStartIndex!==charIndex",charIndex);
                        
                         textData.cells_selectionEnd = charIndex+1 ; // 从左向右选择
                    }
                   
                    else
                    {
                        //console.log("QQ4 单元格选择 dragStartIndex==charIndex",charIndex);
                        if(Math.abs(charIndex-dragStartIndex)>0)
                        textData.cells_selectionEnd = charIndex+1; // 从左向右选择
                        else
                        textData.cells_selectionEnd = charIndex+1; // 从左向右选择
                    }
                    
                    //console.log("QQ4 单元格选择 dragStartIndex：",dragStartIndex," lastPoint:",textData.cells_selectSecond);

                   
                    
                }
                renderText(); // 实时更新文本的渲染以反映选区的变化
            }
        });

        cellsCanvas.addEventListener('mouseout', function(event) {
            isLeftButtonMouseDown = false;
            isDragging = false; // 结束拖拽（选择）
        });
        cellsCanvas.addEventListener('mouseup', function(e) {
            const rect = cellsCanvas.getBoundingClientRect();
            var x = e.clientX - rect.left;
            var y = e.clientY - rect.top;
            //console.log(x, y);

            var   cell_canvasOffset = $('#cellsCanvas').offset();       
            x = x-cell_canvasOffset.left;
            y = y- cell_canvasOffset.top;

            if (e.button === 0) { // 确保是左键引起的mouseup事件
                isDragging = false; // 结束拖拽（选择）
             }
             if (e.button === 0) {
                isLeftButtonMouseDown = false;
            }
            
            if (cells_isSelecting) {
                // 更新选择结束位置
                const charIndex = getCharIndex(x, y);

                if (charIndex >= 0) { // 确保得到了有效的字符索引
                    if (textData.cells_selectionStart !== null) {
                        textData.cells_selectionEnd = charIndex+1 ;
                    } else {
                        textData.cells_selectionStart = charIndex;
                        textData.cells_selectionEnd = charIndex+1 ;
                    }
                }

                if (textData.cells_selectionStart !== null && textData.cells_selectionEnd !== null && textData.cells_selectionStart !== textData.cells_selectionEnd) {
                    // 完成了有效选择
                    textData.cursorVisible = false; // 根据需要隐藏光标
                } else {
                    // 未进行有效选择，可能仅是单击了位置
                    if (charIndex >= 0) {
                        updateCursorPosition(x); // 可能需要更新光标位置函数以适应多行
                    }
                    clearSelection(); // 清除选择
                }
            }

            cells_isSelecting = false; // 重置选择状态
            renderText(); // 重新渲染以应用最终状态
        });


        cellsCanvas.addEventListener('dblclick', function(e) {
            const rect = cellsCanvas.getBoundingClientRect();
            var x = e.clientX - rect.left;
            var y = e.clientY - rect.top;

            var   cell_canvasOffset = $('#cellsCanvas').offset();       
            x = x-cell_canvasOffset.left;
            y = y- cell_canvasOffset.top;

            // 确认点击位置是否在已有的选区内
            if (isInSelection(x, y)) {
                // 如果是在选区内双击，我们需要累计选区内的文本
                let selectedText = "";
                let accumulatedLength = 0; // 累计长度以确定字符的全局索引位置

                for (let line of linesData) {
                    // 对于每一行，检查其是否部分或完全在选区内
                    if (accumulatedLength + line.text.length >= textData.cells_selectionStart && accumulatedLength <= textData.cells_selectionEnd) {
                        // 计算行内选区的开始和结束位置
                        const lineSelectionStart = Math.max(textData.cells_selectionStart - accumulatedLength, 0);
                        const lineSelectionEnd = Math.min(textData.cells_selectionEnd - accumulatedLength, line.text.length);
                        // 累计选区内的文本
                        selectedText += line.text.substring(lineSelectionStart, lineSelectionEnd);
                    }
                    accumulatedLength += line.text.length;
                    // 如果累计长度超过了选区的结束，就不需要继续检查后续的行了
                    if (accumulatedLength > textData.cells_selectionEnd) {
                        break;
                    }
                }

                //console.log("C4 我双击了 ：：",selectedText); // 打印选中的文本到控制台
            }
        });


            function updateStylesForDelete(position, length) {
                //console.log("updateStylesForDelete");
                textData.styles.forEach(style => {
                    if (position < style.start) {
                        style.start -= length;
                        style.end -= length;
                    } else if (position < style.end) {
                        style.end -= length;
                    }

                    // 防止start和end反转
                    if (style.start > style.end) {
                        style.start = style.end;
                    }
                });
            }


            function findCurrentLineIndex(selectionStart) {
                return linesData.findIndex(line => 
                    selectionStart >= line.startIndex && selectionStart < line.startIndex + line.text.length);
            }
            
            function handleArrowUpDown(e) {
                const currentLineIndex = findCurrentLineIndex(textData.cells_selectionStart);
                if (currentLineIndex === -1) return; // Current line not found, exit function
            
                if (e.key === 'ArrowUp' && currentLineIndex > 0) {
                    // Move cursor up
                    const targetLine = linesData[currentLineIndex - 1];
                    const currentXPosition = textData.cells_selectionStart - linesData[currentLineIndex].startIndex;
                    const newPosition = Math.min(targetLine.startIndex + currentXPosition, targetLine.startIndex + targetLine.text.length);
                    textData.cells_selectionStart = newPosition;
                    textData.cells_selectionEnd = newPosition;
                } else if (e.key === 'ArrowDown' && currentLineIndex < linesData.length - 1) {
                    // Move cursor down
                    const targetLine = linesData[currentLineIndex + 1];
                    const currentXPosition = textData.cells_selectionStart - linesData[currentLineIndex].startIndex;
                    const newPosition = Math.min(targetLine.startIndex + currentXPosition, targetLine.startIndex + targetLine.text.length);
                    textData.cells_selectionStart = newPosition;
                    textData.cells_selectionEnd = newPosition;
                }
            }

    document.addEventListener('keydown', function(e) {
                
        //console.log("QQ4 Keydown: " + e.key," isCtrlKey: " + e.ctrlKey,"  textData.cells_selectionStart:", textData.cells_selectionStart);
                  // 检测是否同时按下了Ctrl键和C键
                  if (e.ctrlKey && e.key === 'c') 
                {
                    // 调用复制到剪贴板的函数
                    copyToClipboard();

                    e.preventDefault(); // 防止默认的复制行为
                    return;
                }
             
                  // 检测是否同时按下了Ctrl键和v键
                  if (e.ctrlKey && e.key === 'v') 
                  {
                    messageType=1;//标识为文字输入的消息
                    return;
                  }
               

                  handleArrowUpDown(e);
                // 确保不是控制键，比如箭头键、Backspace等
                if (e.key.length === 1) {
                    // 在这里插入字符到textData.text
                    const beforeCursor = textData.text.slice(0, textData.cells_selectionStart);
                    const afterCursor = textData.text.slice(textData.cells_selectionStart);
                    //console.log("QQ4 英文输入 前：：",textData.text);

                    messageType=1;//标识为文字输入的消息
                
                    textData.text = beforeCursor + e.key + afterCursor;
                    //在这里要调整输入字母的样式 ，增加了一个

                    //console.log("QQ4 英文输入后-> ",textData.text," 插入位置  ",textData.cells_selectionStart);
                    
                    updateStylesForInsert(textData.cells_selectionStart,1);
                    // textData.cells_selectionStart = null;
                    // textData.cells_selectionEnd = null;
                    // 如果需要在取消选择时也隐藏光标，取消以下注释
                    // cells_cursorPosition = null;
                    textData.cursorVisible = true; // 可选：同时隐藏光标
                        // 更新光标位置
                    textData.cells_selectionStart++;
                    hadGen=false;

                    //renderText(); // 重新渲染文本
                }
               
                if (e.key === 'Backspace' &&textData.cells_selectionStart >= 0) {
                    const beforeCursor = textData.text.slice(0, textData.cells_selectionStart - 1);
                    const afterCursor = textData.text.slice(textData.cells_selectionStart);
                    textData.text = beforeCursor + afterCursor;
                    electionStart = null;
                   

                    textData.cells_selectionStart--;
                    if(textData.cells_selectionStart<0)
                    textData.cells_selectionStart=0;
                    textData.cells_selectionEnd= textData.cells_selectionStart;

                    //console.log("QQ4 backspace: ", textData.text);
                    if(textData.text=="")
                    {
                        // 清空fontStyles和fontSize数组
                        textData.fontStyles = [];
                        textData.fontSize = [];
                        textData.background=[];
                        textData.underlineColor=[];

                        textData.fontColor = [];
                        textData.italic = [];
                        textData.bold=[];
                        textData.underline=[];

                        textData.underlineStyle = [];
                        textData.lineThrough = [];
                        textData.background=[];
                        textData.firstLineIndent=0;
                    }
                    hadGen=false;

                    renderText();
                    return;
                } 
                else if (e.key === 'Delete' && textData.cells_selectionStart < textData.text.length) {
                    const beforeCursor = textData.text.slice(0, textData.cells_selectionStart);
                    const afterCursor = textData.text.slice(textData.cells_selectionStart + 1);
                    textData.text = beforeCursor + afterCursor;

                    // 光标位置不变
                    // textData.cells_selectionStart = null;
                    // textData.cells_selectionEnd = null;

                    //console.log("QQ4 Delete: ", textData.text);
                    if(textData.text=="")
                    {
                        // 清空fontStyles和fontSize数组
                        textData.fontStyles = [];
                        textData.fontSize = [];
                        textData.background=[];
                        textData.underlineColor=[];

                        textData.fontColor = [];
                        textData.italic = [];
                        textData.bold=[];
                        textData.underline=[];

                        textData.underlineStyle = [];
                        textData.lineThrough = [];
                        textData.background=[];
                        textData.firstLineIndent=0;
                    }
                    hadGen=false;

                    //renderText();
                }

                if (e.key === 'Enter') {
                    e.preventDefault();  // 阻止默认的回车行为，比如表单提交
        
                    const cursorPos =  textData.cells_selectionStart;  // 获取光标位置
                    const currentText = textData.text;
                    const newText = currentText.slice(0, cursorPos) + '\n' + currentText.slice(cursorPos);
                    textData.text=newText;
                    hadGen=false;
                    messageType=1;//标识为文字输入的消息
                    // // 将光标位置更新到插入换行符后的位置
                    // inputBox.setSelectionRange(cursorPos + 1, cursorPos + 1);
        
                    // // 显示输出（可选）
                    // output.textContent = newText.replace(/\n/g, '\\n');
                }

                if (e.key === 'ArrowLeft' && textData.cells_selectionStart > 0) {
                    textData.cells_selectionStart--;
                   // console.log("《《光标位置移动",textData.cells_selectionStart);
                    //textData.cells_selectionStart = null;
                    textData.cells_selectionEnd = textData.cells_selectionStart;

                    //console.log("QQ4 ArrowLeft: ", textData.text);
                    hadGen=false;
                    
                    //renderText();
                } 
                else if (e.key === 'ArrowRight' && textData.cells_selectionStart <= textData.text.length) {
                    textData.cells_selectionStart++;
                   // console.log("QQ4 光标位置移动=》》",textData.cells_selectionStart);
                    var chartCount=0;

                    cells_charWidths.forEach(objectOfChar => {
                       // console.log('width: '+objectOfChar.width + ' x:' + objectOfChar.x);
                      
                        chartCount++;
                        //console.log("QQ4 ArrowRight: ", textData.text);
                        

                    });

                    if(textData.cells_selectionStart>textData.text.length)
                    textData.cells_selectionStart=textData.text.length;
                    //console.log("QQ4 ArrowRight 光标位置变化: ", textData.cells_selectionStart);
                    // textData.cells_selectionStart = null;
                    textData.cells_selectionEnd = textData.cells_selectionStart;
                    

                    //renderText();
                }

               

        renderText();
    });
    renderText();


    function addEventToButton() {
       
        const CellsEditMenu = document.getElementById('CellsEditMenu');
        const copyMenuItem = document.getElementById('copy');
        const pasteMenuItem = document.getElementById('paste');



        // 点击复制
        copyMenuItem.addEventListener('click', () => {
            copyToClipboard();  // 前面定义的复制函数
            CellsEditMenu.style.display = 'none';  // 隐藏菜单
        });

        // 点击粘贴
        pasteMenuItem.addEventListener('click', () => {
            // 粘贴内容到画布并更新textData.text
            navigator.clipboard.readText().then((text) => {
                // 假设我们粘贴到光标当前位置
                insertTextAtCursor(text);
                messageType=1;//标识为文字输入的消息
                renderText();  // 重新渲染画布
            });
            CellsEditMenu.style.display = 'none';  // 隐藏菜单
        });

        // 点击其他地方时隐藏菜单
        document.addEventListener('click', (e) => {
            if (e.target !== CellsEditMenu) {
                CellsEditMenu.style.display = 'none';
            }
        });
   
        

    }

    function updateForChange()
    {
        compressStyles();                
        generateLinesData();           
        renderText();

    }

    
    function handleCellsEditButtonsClick(event) {
        const target = event.target; // 获取事件的目标元素
        if (target.tagName === 'BUTTON' && target.hasAttribute('data-action')) {
            const action = target.getAttribute('data-action');
            const value = target.getAttribute('data-value');
    
            switch (action) {
                case 'updateSelectedTextSize':
                    updateSelectedTextSize(value);
                    compressStyles();                
                    generateLinesData();   
                   
                    break;
                case 'updateSelectedTextColor':
                    updateSelectedTextColor(value);
                    compressStyles();                
                    generateLinesData();   
                    break;
                case 'updateSelectedFont':
                    updateSelectedFont(value);
                    compressStyles();                
                    generateLinesData();   
                break;
                case 'updateSelectedItalic':
                    updateSelectedItalic((value=="true") ? true : false);
                    compressStyles();                
                    generateLinesData();   
                    break;
                case 'updateSelectedBold':
                    updateSelectedBold((value=="true") ? true : false);
                    compressStyles();                
                    generateLinesData();   
                    break;
                case 'updateSelectedUnderLine':
                    updateSelectedUnderLine((value=="true") ? true : false);
                    compressStyles();                
                    generateLinesData();   
                    break;

                case 'updateSelectedUnderLineStyle':
                    updateSelectedUnderLine(true);
                    updateSelectedUnderLineStyle(value);
                    break;
                case 'updateSelectedUnderLineColor':
                    updateSelectedUnderLine(true);                          
                    updateSelectedUnderLineColor(value);
                    compressStyles();                
                    generateLinesData();   
                    
                    break;
                case 'updateSelectedLineSpacing':
                    updateSelectedLineSpacing(parseInt(value));
                    compressStyles();                
                    generateLinesData();   
                break;
                case 'updateSelectedFirstLineIndent':
                    updateSelectedFirstLineIndent(value);
                    compressStyles();                
                    generateLinesData();   
                    break;
                case 'updateHorizontalAlign':
                    updateHorizontalAlign(value);
                    compressStyles();                
                    generateLinesData();   
                    break;
                case 'updateVerticalAlign':
                    updateVerticalAlign(value);
                    compressStyles();                
                    generateLinesData();   
                    break;

                case 'updateSelectedGBColor':
                    /* The code snippet provided is a comment in JavaScript. It appears to be a
                    function or method name "updateSelectedGBColor" written in a different syntax
                    (possibly a placeholder or pseudocode). The actual implementation of the
                    function is not provided in the given snippet. */
                    updateSelectedGBColor(value);
                    compressStyles();                
                    generateLinesData();   
                    break;
          
                        
                default:
                    console.log('Unknown action:', action);
            }
            renderText();
        }
    }



});

function generateLinesData() {
    linesData = []; // 重置行数据
    
    let currentLineText = '';
    let currentLineStyles = [];
    let cursorX = textArea_offsetX;
    let currentLineMaxHeight = 0;   //当前行的最大字体高度
    let currentLineMinHeight=0;     //最小字体高度
    let currentLineStartIndex = 0;  //记录当前行在原文中的起始位置
    let firstSpacing = true;        //首行缩进所需的空格
    let   indentWidth = 0;          //首行缩进的宽度
    let currentLineWidth=0;
    let isFirstLine=true;
    if(textData.text=="")
    {
        return;
    }

     // 定义占位符及其渲染宽度
    const placeholders = {
        "[checkbox]": null, // 宽度稍后计算，基于字体大小
    };
    

     // 计算首行缩进的宽度
    if (textData.firstLineIndent>0 && textData.text.length > 0) {
        // 找到首字符的样式
        const firstCharFontStyle = textData.fontStyles.find(s => 0 >= s.start && 0 < s.end) || { font: "Arial" };
        const firstCharFontSize = textData.fontSize.find(s => 0 >= s.start && 0 < s.end) || { fontSize: 16 };

        cellsCtx.font = `${firstCharFontSize.fontSize}px ${firstCharFontStyle.font}`;
        // 使用首字符的字体和大小计算一个字符的宽度，然后乘以缩进字符数
        indentWidth = cellsCtx.measureText(" ").width * textData.firstLineIndent;
        cursorX= indentWidth; // 调整首行的起始cursorX值
        currentLineWidth = indentWidth; // Include indent in the line width

        
    }
   

   // console.log("C4 ====generateLinesData cursorX: ",cursorX);

   var charStyle =[];
 
   if(textData.text==null)
   return;
   textData.text.split('').forEach((char, index) => {
    // 查找字符对应的样式，没有则使用默认样式
    const charFont = textData.fontStyles.find(s => index >= s.start && index < s.end) || { font: "Arial" };
    const charFontSize = textData.fontSize.find(s => index >= s.start && index < s.end) || { fontSize: 16 };
    const charColor = textData.fontColor.find(s => index >= s.start && index < s.end) || { color: "black" };
    const charUnderLine = textData.underline.find(s => index >= s.start && index < s.end) || { underline: false };
    const charUnderlineStyle = textData.underlineStyle.find(s => index >= s.start && index < s.end) || { style: "solid" };
    const charUnderlineColor = textData.underlineColor.find(s => index >= s.start && index < s.end) || { color: "red" };
    const charGBColor = textData.background.find(s => index >= s.start && index < s.end) || { background: "transparent" };
     charStyle = {
        font: charFont.font,
        fontSize: charFontSize.fontSize,
        color: charColor.color,
        underline: charUnderLine.underline,
        underlineStyle: charUnderlineStyle.style,
        underlineColor: charUnderlineColor.color,
        background: charGBColor.background,
        start: index - currentLineStartIndex, // 相对于当前行的开始位置
        end: index - currentLineStartIndex + 1 // 相对于当前行的结束位置
    };

    cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
    const metrics = cellsCtx.measureText(char);
    const charWidth = metrics.width;
     // 更新当前行中的最大字体高度
     currentLineMaxHeight = Math.max(currentLineMaxHeight, charStyle.fontSize);

    // 检查字符是否为换行符
    if (char === '\n') {
        // 强制换行处理
        linesData.push({
            text: currentLineText,
            cursorX: firstSpacing ? indentWidth : 0,
            styles: JSON.parse(JSON.stringify(currentLineStyles)),
            y: 0, // 初始y坐标，稍后计算
            lineWidth: currentLineWidth - (firstSpacing ? indentWidth : 0),
            maxHeight: currentLineMaxHeight,
            height: currentLineMaxHeight,
            startIndex: currentLineStartIndex
        });

        // 重置当前行信息，开始新的一行
        firstSpacing = false;
        currentLineText = '';
        currentLineStyles = [];
        cursorX = textArea_offsetX;
        currentLineWidth = 0;
        currentLineMaxHeight = 0;
        currentLineStartIndex = index + 1; // 从下一个字符开始新行
        return; // 继续下一个循环迭代
    }

   

    // 检查是否需要自动换行
    if (cursorX + charWidth > cellsCanvas.width-textArea_offsetX && currentLineText) {
        linesData.push({
            text: currentLineText,
            cursorX: firstSpacing ? indentWidth : 0,
            styles: JSON.parse(JSON.stringify(currentLineStyles)),
            y: 0,
            lineWidth: currentLineWidth - (firstSpacing ? indentWidth : 0),
            maxHeight: currentLineMaxHeight,
            height: currentLineMaxHeight,
            startIndex: currentLineStartIndex
        });

        firstSpacing = false;
        currentLineWidth = charWidth;
        currentLineText = char;
        currentLineStyles = [charStyle];
        cursorX = charWidth;
        currentLineStartIndex = index;
    } else {
        currentLineText += char;
        currentLineStyles.push(charStyle);
        cursorX += charWidth;
        currentLineWidth += charWidth;
    }
});



    // 添加最后一行，如果存在
    if (currentLineText) {
        linesData.push({
            text: currentLineText,
            styles: JSON.parse(JSON.stringify(currentLineStyles)),
            y: 0, // 初始y坐标，稍后计算
            lineWidth: currentLineWidth,
            maxHeight: currentLineMaxHeight,
            height: currentLineMaxHeight,
            startIndex: currentLineStartIndex
        });
    }

    // 现在更新每行的y坐标
    updateLineYCoordinates();
}

function updateLineYCoordinates() {
    let currentY = 0; // 假设文档的起始Y坐标为50
    linesData.forEach(line => {
        line.y = currentY; // 设置当前行的Y坐标
        currentY += line.height + textData.lineSpacing; // 假设行间距为15，更新下一行的起始Y坐标
    });
}

//measureSegment()
//参数：incision:需要切割单元格内容为true,否为false. 切分表示当前页面容量，无法容纳整行单元格。高度不足；
//page_segment:页面剩余容量
//cell_width:  单元格宽度
//cell_height: 单元格高度，逐行输出时判断边界高度
//dist_pages_position_start_x: 目标页面起始位置x
//dist_pages_position_start_y: 目标页面起始位置y
//sour_canvas_position_start_x: 源画布起始位置x
//sour_canvas_position_start_y: 源画布起始位置y
//函数功能：仅对一个单元格的自然段进行绘制，并判断是否超过容量范围，如果是，记录超容这前的位置，并记算出未被容纳的单元格高余量。
function measureSegment(
    incision,
    page_segment,    
    cell_width,
    cell_height,
    dist_pages_position_start_x,
    dist_pages_position_start_y,
    sour_canvas_position_start_x,
    sour_canvas_position_start_y,
    cellObj

) {
   
    
    //console.log("QQ:523==============启动新计划了3点起，8点走=============================");
    let last_page_segment=page_segment;//985-dist_pages_position_start_y%985; //当前页面容量
    hasNoEnoughSpacing=false;//标识当前页有没有足够的空间容纳表格首行文本
    spacingDeviation=0;//页面换行文字高偏差补偿
    totalCellHeight=0;//重新置0
    totalParaSegmentHeight=0;//自然代高度
    maxTextHeight=0;
    upstairs_text_lineHeight=0;
    Hc=cell_height ;  //当前单元格高度
    moveToNextPage=false;
    var textHeight=18;
    
    extHeightFlag=false;
   
    let totalTextHeight = 0;
    let eachLineMaxHeight =0;
    let lineSpacing=0;
    cells_Source_Height=0;   //临时绘制单元格有效高度累计,是文字一行输出后的Y轴的坐标，每输出 一行就要将当前字体大小加行间距一起算进来.
    cells_Dist_Start_Y=0;    //目标页面起始全局坐标.
    if (hadGen == 0) {
        generateLinesData();
        hadGen = 1; // 确保generateLinesData只被调用一次，除非有更新
    }


    if(showParaInCellEdit===true)
        {
            //console.log(`%cQQ:1112 showParaInCellEdit::${showParaInCellEdit}`,'color:green');
        }
    cellsCtx.fillStyle ="transparent";// '#FFFFFF'; // 白色
    cellsCtx.fillRect(0, 0, cellsCanvas.width, cellsCanvas.height); // 填充整个画布

    cellsCtx.clearRect(0, 0, cellsCanvas.width, cellsCanvas.height); // 清除画布，准备新的渲染

    if(linesData==null)
    {
        //console.log("C4 renderText linesData.length<=0  ");
        //console.log(`%cQQ:1112 showParaInCellEdit::${showParaInCellEdit} linesData==null`,'color:red');
        return ;

    }


   
    // 计算整体文本高度
    cellObj.max_text_height_in_cell+=1;
    segmentHeight=cellObj.segmentHeight;
  
     totalTextHeight = 0;
     lineSpacing=  textData.lineSpacing;
    //当前行字符串不为0 逐行输出文字
        if(linesData.length>0) 
        {
          
            totalTextHeight = linesData[linesData.length - 1].y + linesData[linesData.length - 1].maxHeight;
        }   
   

        if(inMeasureAction==1 )//&&debugSN=="Tab001"
        console.log(`%c QQ:614 新单元格绘制开始: 最大列数:${cellObj.max_cell_columns_index} linesData[linesData.length - 1].maxHeight:${linesData[linesData.length - 1].maxHeight} segmentHeight:${cellObj.segmentHeight}  \
        inMeasureAction:${inMeasureAction} debugSN: ${debugSN} cell_height:${cellObj.table_cell_height}  \
        scan_Global_RowOfTable:${ cellObj.rows } current_columns_index:${cellObj.columns}  totalTextHeight:${totalTextHeight}  \
        position_offset_y:${cellObj.position_offset_y} position_offset_y%985:${cellObj.position_offset_y%985} 补偿高:${cellObj.compensating_height}`,"color:green");

       
    maxTextHeight=totalTextHeight>maxTextHeight?totalTextHeight:maxTextHeight;
    //自然段的首行字符串无法在当前页面显示，标识自动在下一页进行绘制
    console.log(`%c QQ:614 cellObj.max_text_height_in_cell: ${cellObj.max_text_height_in_cell}  在measureSegment要取单元格最大高 排除字符被切`, "color: green; background-color: yellow;");
    if(totalTextHeight>last_page_segment)
    {
       // console.log("QQ:523:",maxTextHeight," 页面可容部分空间segmentHeight:",last_page_segment," showParaInCellEdit:",showParaInCellEdit);
        if(maxTextHeight>segmentHeight)
        {
            console.log(`%cQQ:614 可能要跳到下一页哦 maxTextHeight:${maxTextHeight} segmentHeight:${segmentHeight}`,"color:red");
            //TODO: 2024-5-23 4:16 待处理此种情况
            
        }
        
    }
    else
    {
        console.log(`%c QQ:614 可以放得下什么？？？`, "color: green; background-color: yellow;");
    }

       
    // 根据垂直对齐方式计算起始Y坐标偏移
    let startYOffset = 0;
    if (textData.verticalAlign === 'middle') {
        startYOffset = (cellsCanvas.height - totalTextHeight) / 2;
    } else if (textData.verticalAlign === 'bottom') {
        startYOffset = cellsCanvas.height - totalTextHeight;
    }





//切割辅助标记
//下一段切割
var paraNextSegmentPosition=0;  //记录切割位置
let segment_index=0;//切割索引
let remainingHeight=0;//
    cellObj.has_no_cross_cut_line=false;

// 对于顶部对齐，startYOffset保持为0
for (let lineIndex = 0; lineIndex < linesData.length; lineIndex++) {
    let line = linesData[lineIndex];
    //let cursorX = 0; // 每行的起始X坐标
    let maxAscent = 0;
    let maxDescent = 0;
    let lineNo=0;
    let wavyLineStart = null; // 用于记录波浪线起始位置
    let wavyLineColor = "black"; // 默认波浪线颜色
    let cursorX = line.cursorX!==undefined?line.cursorX+textArea_offsetX:textArea_offsetX; // 使用每行特定的cursorX开始渲染
    if(lineIndex==0)
        temp_show_line_Text=line.text;

    
    if (textData.horizontalAlign === 'center') {
        //console.log("C4 horizontalAlign center line.lineWidth: ",line.lineWidth);
        cursorX = (cellsCanvas.width - line.lineWidth) / 2;
    } else if (textData.horizontalAlign === 'right') {
        cursorX = cellsCanvas.width - line.lineWidth;
        //console.log("C4 horizontalAlign center line.right: ",line.lineWidth);
    }


    //console.log("C4 cursorX:",cursorX);
    // 首先，遍历一次以找出每行最大的ascent和descent
    for (let i = 0; i < line.text.length; i++) {
        const charIndex = i + line.startIndex;
        const charStyle = findCharStyle(charIndex);
        cellsCtx.font = `${charStyle.bold ? 'bold ' : ''}${charStyle.italic ? 'italic ' : ''}${charStyle.fontSize}px ${charStyle.font}`;
        const metrics = cellsCtx.measureText(line.text[i]);
        maxAscent = Math.max(maxAscent, metrics.actualBoundingBoxAscent);
        maxDescent = Math.max(maxDescent, metrics.actualBoundingBoxDescent);
      
    }   

        //let baseLineY = line.y + maxAscent; // 使用最大ascent来调整基线，确保垂直对齐
        //textArea_offsetY 在单元格Y轴方向上偏移,避免与边框重叠

        // 获取文本高度
        textHeight = maxAscent + maxDescent;
        const baseLineY = line.y + startYOffset+ maxAscent+ textArea_offsetY; // 调整y坐标，基于垂直对齐偏移
        //const topLineY=line.y+startYOffset+maxAscent;//文字的起始位置线
        const topLineY=line.y+startYOffset+maxAscent- textArea_offsetY;//文字的起始位置线
        currentLineMaxHeight=0;
        // 然后，实际渲染每个字符
         lineNo=lineIndex;
        for (let i = 0; i <= line.text.length; i++) {
            let char = '';          
            if(i<line.text.length)
            char=line.text[i];
            const charIndex = i + line.startIndex;
            const charStyle = findCharStyle(charIndex);
            cellsCtx.font = `${charStyle.bold ? 'bold ' : ''}${charStyle.italic ? 'italic ' : ''}${charStyle.fontSize}px ${charStyle.font}`;
            eachLineMaxHeight=Math.max(eachLineMaxHeight,parseInt(charStyle.fontSize));
            cellsCtx.fillStyle = charStyle.color;
            const metrics = cellsCtx.measureText(char);     
            // 绘制字符
            // 继续使用字符的前景色绘制字符
            cellsCtx.fillStyle = charStyle.color;
            cellsCtx.fillText(char, cursorX, baseLineY);
            //console.log("最大行高：",currentLineMaxHeight);  
            cells_charWidths[i] = { width: metrics.width, x: cursorX };
            cursorX += metrics.width;
        }

        dist_copy_cell_height=cell_height;      
  ////是首行？
    //表格单元格首行检测
  if(cellObj.rows==0){

                        //3.1.2.1 是! 能容下首行字符串
                          //当前页的剩余容量与当前文字高度相比 可得出 首行文字是否可放得下
                       if(lineIndex==0)
                        {       //当前页面可以容纳第一行内容
                                if(cellObj.segmentHeight>textHeight)
                                {   
                                       tempSegmentPosition=baseLineY+maxDescent;
                                     
                                       first_line_text_height=tempSegmentPosition+cellObj.spacing_height;
                                        cells_source_offset_rest_page=textHeight;//3.1.2.1.1计算出剩下容量，作为偏移; 即记录上一次最大的首行单元格文字行可容的位置 
                                        cells_Source_Height+=textHeight+cellObj.spacing_height;                       //保留最近一行段落行距;//计算每行文字输出后的和
                                        if(inMeasureAction==1 )
                                        {
                                            //columns 吃藕撸面能分列
                                            console.log(`%c QQ:614 debug:${debugSN} 行:${lineNo} 列:${cellObj.columns}  首行放得下文字首行: textHeight${textHeight}  segmentHeight:${segmentHeight} ;cell_height:${cellObj.table_cell_height} tempSegmentPosition(单行文字占位高):${tempSegmentPosition} ; cellsIndex:${current_columns_index}   text:${line.text}`,"color:blue");
                  
                                        }
                                   
                                    
                                }
                                else
                                {
                                    hasNoEnoughSpacing=true;
                                    if(inMeasureAction==1&&debugSN=="Tab001" )
                                        {
                                            console.log(`%c QQ:614 debug:${debugSN} 行:${lineNo} 列:${cellObj.columns}  首行放不下文字首行: textHeight${textHeight} segmentHeight:${segmentHeight} ;cell_height:${cellObj.table_cell_height} tempSegmentPosition(单行文字占位高):${tempSegmentPosition} ; cellsIndex:${current_columns_index}   text:${line.text}`,"color:blue");
                  
                                        }
                                    if(inMeasure) //表格首行不够位置，，标为空间不够，以便跳页
                                       return;

                                }
                           
                           //可以放得下首行表格内的首行字符串, 什么也不用做;
                        }
                        else
                        {   //非首行字符绘制
                            console.log(`%c QQ:614 debug:${debugSN} 行:${lineNo} 列:${cellObj.columns}  非首行绘制`,"color:red");
                            //3.1.2.1.1计算出剩下容量，作为偏移offset_rest_page
                            // 切割信息
                            // A:从哪里取，起始位置多少，取多高，多宽？
                            // 1. 起始坐标:  cells_Source_Start_X/Y;
                            // 2. 高度:         cells_Source_Height;
                            // 3. 宽度:         cells_Source_Width;

                            // B:取到之后放到哪里去？
                            // 1. 起始坐标：cells_Dist_Start_X/Y;  通过页面大小，可以计算出所在页；
                            // 2. 高度：      cells_Dist_Height;
                            // 3. 宽度：      cells_Dist_Width;

                            // C: 切割类型 cut_type：0 首行不足，跳页；
                            //                     1 横切，要补首尾线；
                            // D: 对像类别 paraType：0 自然段，1 表格

                                if(lineIndex!=0)
                                {
                                    lastSegmentPosition=current_cell_position_y ;
                                    cells_Dist_Start_Y=current_cell_position_y;
                                    cells_Dist_Height=cells_Source_Height;
                                    cells_Dist_action=1;//1表示页尾不足，写完要跳转一新页

                                    //measureSegment()
                                    //参数：incision:需要切割单元格内容为true,否为false. 切分表示当前页面容量，无法容纳整行单元格。高度不足；
                                    //cell_width:  单元格宽度
                                    //cell_height: 单元格高度，逐行输出时判断边界高度
                                    //dist_pages_position_start_x: 目标页面起始位置x
                                    //dist_pages_position_start_y: 目标页面起始位置y
                                    //sour_canvas_position_start_x: 源画布起始位置x
                                    //sour_canvas_position_start_y: 源画布起始位置y


                                    //页面与表格单元格绘制规则模型
                                    //***************************************************/
                                    // var Hp=985; //页面高度
                                    // var Hct=0;  //下半页单元格累计高度  Hct<=Hp
                                    // var Hc=0 ;  //当前单元格高度
                                    // var Hs=0 ;  //上半截单元格高度（当一页容不下一行单元格时）
                                    // var Ha=0 ;  //Ha=Hc-Hs
                                    // var Has=0;  //下半截页面可用高度
                                    //***************************************************/
                                    Hs=cells_Source_Height;//记住上半截单元格高度
                                    Hct=Hs;
                                    if(inMeasureAction==1)
                                    {         

                                        console.log(`%c QQ:614  这里发生切割debugSN:${debugSN} lineNo:${lineNo} dist_pages_position_start_y:${cellObj.position_offset_y} sour_canvas_position_start_y:${sour_canvas_position_start_y} cells_Source_Height:${cells_Source_Height} segmentHeight:${segmentHeight} ;current_tables_canvas_drawing_position_y:${current_tables_canvas_drawing_position_y} 上一行的高:${cells_source_offset_rest_page}  text:${line.text}`,"color:blue");
                                    }

                                    //5-23切割要记录的内容：
                                    //1.形成当前的切块，包括两部分数据，1是拷贝源 的起始与高度；2是目标源的起始坐标与高度；
                                    //2.记录最后一次拷贝源, 目标源 分别的结束位置。将做来下一次分块的起点位置.
                                    //3. 由于两都高度是一样的，只需要一个source_copy_block_height来表示即可。
                                    //4. 保存最后一个单元格高度
                                    //重新定义 这个坐标为全局绝对坐标，包括页面偏移： 
                                    // var source_copy_start_position_y=0;
                                    // var source_copy_block_height=0;
                                    // var dist_copy_start_position_y=0;
                                    // var dist_copy_cell_height=0;
                                    
                                                              

                                     var newSegment1 = {

                                        segment_index: 0,
                                        inMeasure:inMeasure,
                                        debugSn:debugSN,
                                        cells_Dist_Start_Y:cellObj.position_offset_y,
                                        cells_Dist_Height:cells_Dist_Height,
                                        cells_Source_Start_Y:current_tables_canvas_drawing_position_y,
                                        sliceType:1,
                                        offset_X: 0,
                                        offset_Y: lastSegmentPosition,
                                        width: 700,
                                        height: cells_Source_Height,
                                        pageOffsetY:segmentHeight,
                                        lineText:line.text,
                                        dataSource:"切割开1:判断一个首行单元格的字符是否能被完整显示，如果不能，再判断这个表格高度是否小于一个页面985"
                                        
                                        };
                                                               // segment_Info.push(newSegment1);
                                
                                        checkDuplicateAndInsert(segment_Info, newSegment1);

                                    //5-23 当切块发生变化时，更新源与目标源的偏移
                                    source_copy_block_height=cells_Dist_Height;
                                    source_copy_start_position_y+=source_copy_block_height;
                                    dist_copy_start_position_y+=source_copy_block_height;

                                    current_tables_canvas_drawing_position_y+=cells_Source_Height;
                                    offsetHeaderLine=baseLineY;
                                    //moveToNextPage=true;
                                    break;
                                }
                                                          
                        }

  } //处理表格单元格首行完毕
  else { //非首行单元格检测
       
           //3.1.2.2 否! 获取当前页面空间及文本高
            if(inMeasureAction==1&&debugSN=="Tab001" )
             console.log(`%c QQ:614  非首行单元格 segmentHeight:${segmentHeight} row:${scan_Global_RowOfTable} ; cellsIndex:${current_columns_index} text:${line.text}`,"color:red;background-color: yellow;");

      if(segmentHeight>(textHeight))
       {   
            tempSegmentPosition=baseLineY+maxDescent;
            let myLast_Source_height=cells_Source_Height;//保存临时上一行的高度，如果出现超页，就会用之前这个数据。。

            cells_source_offset_rest_page=textHeight;//3.1.2.1.1计算出剩下容量，作为偏移; 即记录上一次最大的首行单元格文字行可容的位置 
            cells_Source_Height+=textHeight+lineSpacing;//计算每行文字输出后的和
                if(cells_Source_Height<segmentHeight)
                {  
                    lastSegmentPosition+=textHeight+lineSpacing;
                    if(inMeasureAction==1&&debugSN=="Tab001" )
                    {
                        console.log(`%c QQ:614  非首行放得-------下文字首行line:${lineNo} cells_Source_Height:${cells_Source_Height} segmentHeight:${segmentHeight} ;cell_height:${cellObj.table_cell_height} tempSegmentPosition:${tempSegmentPosition} ; cellsIndex:${current_columns_index}`,"color:blue");

                    }

                }
                else
                {
                    if(inMeasureAction==1 )
                    {
                        console.log(`%c QQ:614  非首行放不下所有文字 本页表格列高:${dist_total_cells_height+myLast_Source_height} current_tables_canvas_drawing_position_y:${current_tables_canvas_drawing_position_y} dist_total_cells_height:${dist_total_cells_height} cells_Dist_Start_Y:${cells_Dist_Start_Y} pageGlobalYPosition${pageGlobalYPosition} debugSN:${debugSN} cells_Source_Height:${myLast_Source_height} line:${lineNo} line.text${line.text} cells_Source_Height:${cells_Source_Height} segmentHeight:${segmentHeight} ;cell_height:${cellObj.table_cell_height} tempSegmentPosition:${tempSegmentPosition} ; cellsIndex:${current_columns_index}`,"color:blue");

                    }
            
                            
                    if(inMeasure) //表格首行不够位置，，标为空间不够，以便跳页
                    return;
                }
                              
                           
                            
                        }
                        else
                        {
                           
                           // lastSegmentPosition=current_cell_position_y ;
                            cells_Dist_Start_Y=current_cell_position_y;
                            cells_Dist_Height=cells_Source_Height;
                            cells_Dist_action=1;//1表示页尾不足，写完要跳转一新页
                            is_on_bottom_of_page=true;//表示页尾不足，绘制完成后要做补偏页面起点
                             if(inMeasureAction==1 )
                                {                                            
                                 console.log(`%c QQ:614  非首行单元格这里发生切割: cells_Dist_Start_Y:${cells_Dist_Start_Y} cells_Source_Height:${cells_Source_Height} segmentHeight:${segmentHeight} ;current_tables_canvas_drawing_position_y:${current_tables_canvas_drawing_position_y} 上一行的高:${cells_source_offset_rest_page}`,"color:blue");
                                }
                            
                           

                             var newSegment1 = {
                                                        segment_index: 0,
                                                        inMeasure:inMeasure,
                                                        debugSn:debugSN,
                                                        cells_Dist_Start_Y:cells_Dist_Start_Y,
                                                        cells_Dist_Height:cells_Dist_Height,
                                                        cells_Source_Start_Y:current_tables_canvas_drawing_position_y,
                                                        sliceType:1,
                                                        offset_X: 0,
                                                        offset_Y: lastSegmentPosition,
                                                        width: 700,
                                                        height: cells_Source_Height,
                                                        pageOffsetY:segmentHeight,
                                                        lineText:line.text,
                                                        dataSource:"切割开12:判断一个首行单元格的字符是否能被完整显示"
                                                       
                                                        };
                                                       // segment_Info.push(newSegment1);
                        
                                                        checkDuplicateAndInsert(segment_Info, newSegment1);
                                                        current_tables_canvas_drawing_position_y+=cells_Source_Height;
                            
                       
                            if(inMeasure) //表格首行不够位置，，标为空间不够，以便跳页
                               return;

                        }

  }
            

    //打印自然段与页面信息
    if(inMeasureAction==1)
    {
        console.log(`%c QQ:614 debug${debugSN} 当前偏移:${baseLineY+maxDescent+lineSpacing} lineSpacing:${lineSpacing} 当前可用空间:${segmentHeight} position%985:${985-cellObj.position_offset_y%985 } 行距:${cellObj.spacing_height} 文字高:${tempSegmentPosition} 单元格首行使用高度:${first_line_text_height}\
             本列高还有另一下半部高: ${cellObj.table_cell_height-first_line_text_height} 有一种可能它默默走完一生，这些文字都不会跨过下半页--`,'color:red');
    }
        
        //绘制完一行后，需要判断是否需要切割单元格
        //如果需要切割单元格，则需要记录当前单元格的起始位置和高度
        //console.log("QQ:111 观察单元格:",single_table_cell_index," text_line_height:",currentLineMaxHeight);
        if((baseLineY+maxDescent+lineSpacing)>=segmentHeight)//baseLineY在当前行内，需要截断
        {
            //切割开2:超过segmentHeight
               
          console.log(`%c QQ:614--------------------------: 正在输出的文本高超过了 容量 全文高度:",${tempSegmentPosition}," ${showParaInCellEdit}:",${showParaInCellEdit}`,"color:blue");
              
                 paraNextSegmentPosition=baseLineY+maxDescent;//记录还没有被切的单元格的高度
                if(showParaInCellEdit==true)
                {
                    //这里要计算了出补偿量
                    totalParaSegmentHeight=maxTextHeight;
                   
                    lastSegmentPosition=tempSegmentPosition;
                    //console.log(`%c QQ:1115  ,upstairs_cells_height:${upstairs_cells_height} 理想切割点YPosition:${985-tempSegmentPosition} , 当前光标位置:${tempSegmentPosition},segmentHeight：${segmentHeight} 光标位置+文字高+换行间隙：${tempSegmentPosition+lineHeight+lineSpacing} paraNextSegmentPosition:${paraNextSegmentPosition}`,"color:red");
                    //console.log("QQ:1115: 正在输出的文本高超过了 容量 全文高度:",maxTextHeight," SN:",debugSN," paraNextSegmentPosition:",paraNextSegmentPosition," 第一页面可容部分空间segmentHeight:",segmentHeight," 完整切割文高:"+tempSegmentPosition," baseLineY+maxDescent:", baseLineY+maxDescent," showParaInCellEdit:",showParaInCellEdit," line:",line.text);

                       if(lastSegmentPosition>0)
                        {
                            if(spacingDeviation==0)
                             spacingDeviation+=segmentHeight-tempSegmentPosition;
                          
                            var newSegment1 = {
                                segment_index: 0,
                                inMeasure:inMeasure,
                                sliceType:0,
                                debugSn:debugSN,
                                cells_Dist_Start_Y:cells_Dist_Start_Y,
                                cells_Dist_Height:cells_Dist_Height,
                                offset_X: 0,
                                offset_Y: 985-tempSegmentPosition,
                                width: 701,
                                height: tempSegmentPosition,
                                pageOffsetY:segmentHeight,
                                dataSource:"切割开2 : 超过segmentHeight "
                                };
                               // segment_Info.push(newSegment1);
 ////当前列未绘制完的下半截=当前的列高-实际文字高
 cellObj.compensating_height=cellObj.table_cell_height-(upstairs_cells_height+tempSegmentPosition); //当前列未绘制完的下半截
 console.log(`%c QQ:614: 当前决断 此时：debug:${debugSN} 行:${lineNo} 列:${cellObj.columns} cellObj.table_cell_height:${cellObj.table_cell_height} compensating_height:${cellObj.compensating_height} cellObj.max_text_height_in_cell:${cellObj.max_text_height_in_cell},行距:${cellObj.spacing_height} 第一页面可容部分空间segmentHeight:${segmentHeight}, 完整切割文高:${tempSegmentPosition}, upstairs_cells_height:${upstairs_cells_height}, 实际高度:${upstairs_cells_height+tempSegmentPosition}, index: ${segment_index}, line:${line.text} ;where to call:${where_to_call}`,"color:blue");
  
                            let myCheck=    checkDuplicateAndInsert(segment_Info, newSegment1);
                              
                             
                              if(!myCheck)
                                {     //console.log(`%c QQ:1115  理想切割点:${tempSegmentPosition} myCheck:${myCheck} `, "color:green");
                                      segmentHeight=985; //下一页的容量是
                                      cellObj.max_text_height_in_cell=0;
                                      tempSegmentPosition=0;
                                }

                        }
                }
      
        }
        else //segmentHeight>baseLineY+maxDescent 正常区域内
        {
          
            tempSegmentPosition=baseLineY+maxDescent+cellObj.spacing_height;
           
            //如果此时tempSegmentPosition已经超过了最大高度，则需要切割单元格  
            //为下一页的单元格内容做准备
            //计算出剩余的内容高度
            remainingHeight=maxTextHeight-tempSegmentPosition; 
            //cellObj.compensating_height=cellObj.table_cell_height-tempSegmentPosition;
            //" 实际高度:",upstairs_cells_height+tempSegmentPosition
            //" 完整切割文高:"+tempSegmentPosition
            cellObj.found_position_section=true; //标识找到切口位置
            console.log("QQ:614 前面列补尝:",cellObj.compensating_height);
            cellObj.max_text_height_in_cell=tempSegmentPosition+cellObj.compensating_height;//切口高度
            cellObj.last_max_text_height_in_cell=cellObj.max_text_height_in_cell;
            console.log(`%c QQ:614: 逐行到放不下为止 此时：debug:${debugSN} 行:${lineNo} 列:${cellObj.columns} cellObj.table_cell_height:${cellObj.table_cell_height} compensating_height:${cellObj.compensating_height} 全文高度:${maxTextHeight},行距:${cellObj.spacing_height} 第一页面可容部分空间segmentHeight:${segmentHeight}, 完整切割文高:${tempSegmentPosition}, upstairs_cells_height:${upstairs_cells_height}, 实际高度:${upstairs_cells_height+tempSegmentPosition}, index: ${segment_index}, line:${line.text} ;where to call:${where_to_call}`,"color:blue");
            
           
            cellObj.is_on_bottom_of_page=true;
            segment_index+=tempSegmentPosition;
            console.log(`%c QQ:614: 逐行到放不下为止补偿后 此时：debug:${debugSN} 行:${lineNo} 列:${cellObj.columns} cellObj.table_cell_height:${cellObj.table_cell_height} compensating_height:${cellObj.compensating_height} cellObj.max_text_height_in_cell:${cellObj.max_text_height_in_cell},行距:${cellObj.spacing_height} 第一页面可容部分空间segmentHeight:${segmentHeight}, 完整切割文高:${tempSegmentPosition}, upstairs_cells_height:${upstairs_cells_height}, 实际高度:${upstairs_cells_height+tempSegmentPosition}, index: ${segment_index}, line:${line.text} ;where to call:${where_to_call}`,"color:blue");
            cellObj.max_segment_height_in_no_cross=true;//没有切口，意味着文字在上半截是安全的。
          
        }
        let underLineM=baseLineY+lineSpacing;
       

        //drawWavyUnderline(wavyLineStart, underLineM, cursorX - wavyLineStart, "green");
        //drawWavyUnderline(wavyLineStart, topLineY-lineSpacing, cursorX - wavyLineStart, "black");

        //判断是不是最后一行，如果是最后一行，不要行距。
        let totalLines=linesData.length;
        if(lineIndex<totalLines-1)
        totalCellHeight=totalCellHeight+ eachLineMaxHeight+textData.lineSpacing;
         else 
        totalCellHeight=totalCellHeight+eachLineMaxHeight+textArea_offsetY; //加上顶行


      
            // 行末处理，确保波浪线被绘制
            if (wavyLineStart !== null) {
                const underlineY = baseLineY + 5; // 基线下方的Y坐标
                drawWavyUnderline(wavyLineStart, underlineY, cursorX - wavyLineStart, underlineColor);
            }
};


cellObj.has_no_cross_cut_line=true;
cellObj.max_segment_height_in_no_cross=cellObj.table_cell_height-cellObj.segmentHeight;     

       if(hasToCutCells==true)
        {
            cellsCompareData.push({
                textHeight: totalTextHeight,
                segmentHeight: segmentHeight,
                cellsHeight: tempSegmentPosition,
                columnsIndex: current_columns_index
            });
            //console.log("QQ5: cellsHeight",tempSegmentPosition," segmentHeight:",segmentHeight);

        }


console.log("614: 段落总高度：",totalCellHeight," segment_height:",cellObj.segmentHeight," 单元格高：",cellsCanvas.height,"cellObj.max_segment_height_in_no_cross:",cellObj.max_segment_height_in_no_cross);
if(totalCellHeight>cellsCanvas.height) {
    extHeightFlag=true;

    var messageToSend = "这是一条通过事件总线传递的消息";
    if(lastMessage!=totalCellHeight)
    {
        EventBus.trigger("customMessage", totalCellHeight);
        lastMessage=totalCellHeight;//消息生产

    }
   

}
}

function renderText() {
   

        hasNoEnoughSpacing=false;//标识当前页有没有足够的空间容纳表格首行文本
        spacingDeviation=0;//页面换行文字高偏差补偿
        totalCellHeight=0;//重新置0
        totalParaSegmentHeight=0;//自然代高度
        maxTextHeight=0;
        upstairs_text_lineHeight=0;
       
        moveToNextPage=false;        
        extHeightFlag=false;
       
        let totalTextHeight = 0;
        let eachLineMaxHeight =0;

        cells_Source_Height=0;   //临时绘制单元格有效高度累计,是文字一行输出后的Y轴的坐标，每输出 一行就要将当前字体大小加行间距一起算进来.
        cells_Dist_Start_Y=0;    //目标页面起始全局坐标.
        if (hadGen == 0) {
            generateLinesData();
            hadGen = 1; // 确保generateLinesData只被调用一次，除非有更新
        }

 
        if(showParaInCellEdit===true)
            {
                //console.log(`%cQQ:1112 showParaInCellEdit::${showParaInCellEdit}`,'color:green');
            }
        cellsCtx.fillStyle ="transparent";// '#FFFFFF'; // 白色
        cellsCtx.fillRect(0, 0, cellsCanvas.width, cellsCanvas.height); // 填充整个画布

        cellsCtx.clearRect(0, 0, cellsCanvas.width, cellsCanvas.height); // 清除画布，准备新的渲染
    
        if(linesData==null)
        {
            //console.log("C4 renderText linesData.length<=0  ");
            //console.log(`%cQQ:1112 showParaInCellEdit::${showParaInCellEdit} linesData==null`,'color:red');
            return ;

        }




        // if(inMeasureAction==1 )
        // console.log(`%c QQ62 segmentHeight:${segmentHeight} inMeasureAction:${inMeasureAction} current_cell_height:${current_cell_height} current_cell_position_y:${current_cell_position_y} debugSN: ${debugSN} scan_Global_RowOfTable:${ scan_Global_RowOfTable } current_columns_index:${current_columns_index}`,"color:green");
        // // 计算整体文本高度
         totalTextHeight = 0;
         lineSpacing=  textData.lineSpacing;
        
        if(linesData.length>0)    
        totalTextHeight = linesData[linesData.length - 1].y + linesData[linesData.length - 1].maxHeight;
        
           
                maxTextHeight=totalTextHeight>maxTextHeight?totalTextHeight:maxTextHeight;
               
               

           
        // 根据垂直对齐方式计算起始Y坐标偏移
        let startYOffset = 0;
        if (textData.verticalAlign === 'middle') {
            startYOffset = (cellsCanvas.height - totalTextHeight) / 2;
        } else if (textData.verticalAlign === 'bottom') {
            startYOffset = cellsCanvas.height - totalTextHeight;
        }

            if(showParaInCellEdit===true)
            {
                //console.log(`%cQQ:1112 lineSpacing:${lineSpacing}`,'color:red');
            }




    
    // 对于顶部对齐，startYOffset保持为0
    // linesData.forEach((line, lineIndex) => {
    for (let lineIndex = 0; lineIndex < linesData.length; lineIndex++) {
        let line = linesData[lineIndex];

        //let cursorX = 0; // 每行的起始X坐标
        let maxAscent = 0;
        let maxDescent = 0;
        let lineNo=0;
        let wavyLineStart = null; // 用于记录波浪线起始位置
        let wavyLineColor = "black"; // 默认波浪线颜色
        let cursorX = line.cursorX!==undefined?line.cursorX+textArea_offsetX:textArea_offsetX; // 使用每行特定的cursorX开始渲染
        if(lineIndex==0)
            temp_show_line_Text=line.text;

        
       
        //console.log("C4 cursorX:",cursorX);

        
        if (textData.horizontalAlign === 'center') {
            //console.log("C4 horizontalAlign center line.lineWidth: ",line.lineWidth);
            cursorX = (cellsCanvas.width - line.lineWidth) / 2;
        } else if (textData.horizontalAlign === 'right') {
            cursorX = cellsCanvas.width - line.lineWidth;
            //console.log("C4 horizontalAlign center line.right: ",line.lineWidth);
        }

   
        //console.log("C4 cursorX:",cursorX);
        // 首先，遍历一次以找出每行最大的ascent和descent
        for (let i = 0; i < line.text.length; i++) {
            const charIndex = i + line.startIndex;
            const charStyle = findCharStyle(charIndex);
            cellsCtx.font = `${charStyle.bold ? 'bold ' : ''}${charStyle.italic ? 'italic ' : ''}${charStyle.fontSize}px ${charStyle.font}`;
            const metrics = cellsCtx.measureText(line.text[i]);
            maxAscent = Math.max(maxAscent, metrics.actualBoundingBoxAscent);
            maxDescent = Math.max(maxDescent, metrics.actualBoundingBoxDescent);
          
        }   

            //let baseLineY = line.y + maxAscent; // 使用最大ascent来调整基线，确保垂直对齐
            //textArea_offsetY 在单元格Y轴方向上偏移,避免与边框重叠

            // 获取文本高度
            textHeight = maxAscent + maxDescent;

         
            const baseLineY = line.y + startYOffset+ maxAscent+ textArea_offsetY; // 调整y坐标，基于垂直对齐偏移
            //const topLineY=line.y+startYOffset+maxAscent;//文字的起始位置线
            currentLineMaxHeight=0;
            // 然后，实际渲染每个字符

             lineNo=lineIndex;
            for (let i = 0; i <= line.text.length; i++) {
                let char = '';//
              
                if(i<line.text.length)
                char=line.text[i];
                const charIndex = i + line.startIndex;
                const charStyle = findCharStyle(charIndex);
            // console.log("C4 charStyle.underlineColor:",charStyle.underlineColor," char:",line.text[i]);
                var underlineColor = charStyle.underlineColor || "black"; 

                cellsCtx.font = `${charStyle.bold ? 'bold ' : ''}${charStyle.italic ? 'italic ' : ''}${charStyle.fontSize}px ${charStyle.font}`;
               eachLineMaxHeight=Math.max(eachLineMaxHeight,parseInt(charStyle.fontSize));
                cellsCtx.fillStyle = charStyle.color;
                const metrics = cellsCtx.measureText(char);

                

                // 在绘制字符之前绘制背景色，如果定义了背景色
                if (charStyle.background) {
                    cellsCtx.fillStyle = charStyle.background;
                    const metrics = cellsCtx.measureText(char);
                    // 考虑行高(maxAscent + maxDescent)来填充背景色
                    cellsCtx.fillRect(cursorX, baseLineY - maxAscent, metrics.width, maxAscent + maxDescent);
                }

                // 如果字符处于选中状态，绘制高亮背景
                    if (isCharSelected(charIndex)) {
                        const metrics = cellsCtx.measureText(char);
                        cellsCtx.fillStyle = 'rgba(0, 0, 0, 0.5)'; // 高亮颜色，可自定义
                        cellsCtx.fillRect(cursorX, baseLineY - maxAscent, metrics.width, maxAscent + maxDescent);
                        cellsCtx.fillStyle = charStyle.color; // 重置为字符颜色以便绘制文本
                    }

                
                // 绘制字符
                // 继续使用字符的前景色绘制字符
                cellsCtx.fillStyle = charStyle.color;
                cellsCtx.fillText(char, cursorX, baseLineY);

             
               

                //console.log("最大行高：",currentLineMaxHeight);
                if(textData.cells_selectionStart!=null)
                {

            
                    if(textData.cells_selectionStart === charIndex )//&&textData.cells_selectionStart==textData.cells_selectionEnd 
                    {
                    // console.log("QQ3 开始绘制光标:", textData.cells_selectionStart ," start:",textData.cells_selectionStart," end:",textData.cells_selectionEnd);
                        cellsCtx.beginPath();
                        cellsCtx.moveTo(cursorX, baseLineY+charStyle.fontSize/4);
                        cellsCtx.lineTo(cursorX, baseLineY - charStyle.fontSize);
                    
                        if(textData.cursorVisible)
                        cellsCtx.strokeStyle = 'black';
                        else
                        cellsCtx.strokeStyle = 'transparent';
                        cellsCtx.lineWidth = 2;
                        cellsCtx.stroke();

                    } 
                }
                else
                {
                // console.log("QQ3 Error 开始绘制光标: textData.cells_selectionStart==null");
                
                }


                cells_charWidths[i] = { width: metrics.width, x: cursorX };

                var underlineY = baseLineY + 5; // 基线下方的Y坐标
                // 处理下划线
                
                if (charStyle.underline) {
                    underlineY = baseLineY + 5; // 基线下方的Y坐标
                    
                    if (charStyle.underlineStyle === 'wavy') {
                        if (wavyLineStart === null) {
                            wavyLineStart = cursorX;
                            wavyLineColor = underlineColor; // 记录波浪线颜色

                        // console.log("C4 wavy line color: " + wavyLineColor);
                        }

                        
                    } else {
                        if (wavyLineStart !== null) {
                            drawWavyUnderline(wavyLineStart, underlineY, cursorX - wavyLineStart, wavyLineColor);
                            wavyLineStart = null;
                    
                        }
                        drawUnderline(cursorX, underlineY, metrics.width, underlineColor, charStyle.underlineColor);
                    }
                } else if (wavyLineStart !== null) {
                    drawWavyUnderline(wavyLineStart, underlineY, cursorX - wavyLineStart, wavyLineColor);
                    wavyLineStart = null;
                }

                cursorX += metrics.width;
            }

            //drawWavyUnderline(wavyLineStart, underLineM, cursorX - wavyLineStart, "green");
            //drawWavyUnderline(wavyLineStart, topLineY-lineSpacing, cursorX - wavyLineStart, "black");

            //判断是不是最后一行，如果是最后一行，不要行距。
            let totalLines=linesData.length;
            if(lineIndex<totalLines-1)
            totalCellHeight=totalCellHeight+ eachLineMaxHeight+textData.lineSpacing;
             else 
            totalCellHeight=totalCellHeight+eachLineMaxHeight+textArea_offsetY; //加上顶行


          
                // 行末处理，确保波浪线被绘制
                if (wavyLineStart !== null) {
                    const underlineY = baseLineY + 5; // 基线下方的Y坐标
                    drawWavyUnderline(wavyLineStart, underlineY, cursorX - wavyLineStart, underlineColor);
                }
    };

   
   		



    if(totalCellHeight>cellsCanvas.height) {
        extHeightFlag=true;

        var messageToSend = "这是一条通过事件总线传递的消息";
        if(lastMessage!=totalCellHeight)
        {
            EventBus.trigger("customMessage", totalCellHeight);
            lastMessage=totalCellHeight;//消息生产

        }
       

    }

            // 将 canvas 内容导出为 Data URL 格式
// var dataURL = cellsCanvas.toDataURL('image/png');

// // 创建一个 a 标签并模拟点击,触发文件下载
// var link = document.createElement('a');
// link.download = 'render canvas_image.png';
// link.href = dataURL;
// link.click();

}

function findCharStyle(index) {
    const charFont = textData.fontStyles.find(s => index >= s.start && index < s.end) || { font: "Arial" };
    const charFontSize = textData.fontSize.find(s => index >= s.start && index < s.end) || { fontSize: 16 };
    const charColor = textData.fontColor.find(s => index >= s.start && index < s.end) || { color: "black" };
    const charItalic = textData.italic.find(s => index >= s.start && index < s.end) || { italic: false };
    const charBold = textData.bold.find(s => index >= s.start && index < s.end) || { bold: false };
    const charUnderline = textData.underline.find(s => index >= s.start && index < s.end) || { underline: false };
    const charLineThrough = textData.lineThrough.find(s => index >= s.start && index < s.end) || { lineThrough: false };
    const charBackground = textData.background.find(s => index >= s.start && index < s.end) || { background: "transparent" };
    const charUnderlineStyle=textData.underlineStyle.find(s => index >= s.start && index < s.end) || {style: 'wavy'};
    const charUnderlineColor = textData.underlineColor.find(s => index >= s.start && index < s.end) || { color: "red" };
    

    return {
        font: charFont.font,
        fontSize: charFontSize.fontSize,
        color: charColor.color,
        italic: charItalic.italic,
        bold: charBold.bold,
        underline: charUnderline.underline,
        lineThrough: charLineThrough.lineThrough,
        background: charBackground.background,
        underline: charUnderline.underline,
        underlineColor: charUnderlineColor.color,
        underlineStyle: charUnderlineStyle.style
    };
}
function isCharSelected(index) {
    // 假设有全局变量cells_selectionStart和cells_selectionEnd定义了选区的开始和结束
    //console.log("QQ2 isCharSelected start:",textData.cells_selectionStart," end:",textData.cells_selectionEnd);
    return index >= textData.cells_selectionStart && index < textData.cells_selectionEnd&&textData.cells_selectionStart!=textData.cells_selectSecond;
}


function drawUnderline(x, y, width, color, style) {
    cellsCtx.beginPath();
    cellsCtx.strokeStyle = color;
    cellsCtx.moveTo(x, y);
    cellsCtx.lineTo(x + width, y);
    cellsCtx.stroke();

    if (style === 'double') {
        cellsCtx.moveTo(x, y + 2);
        cellsCtx.lineTo(x + width, y + 2);
        cellsCtx.stroke();
    }
}


function drawWavyUnderline(x, y, width, color) {
    cellsCtx.beginPath();
    cellsCtx.strokeStyle = color;
    let amplitude = 3;
    let frequency = 5;
    for (let i = x; i <= x + width; i += frequency) {
        cellsCtx.quadraticCurveTo(
            i + frequency / 4,
            y + ((i % (frequency * 2)) < frequency ? amplitude : -amplitude),
            i + frequency / 2,
            y
        );
    }
    cellsCtx.stroke();
}







    function highlightSelection(highlightColor) {
        highlightColor = 'rgba(173, 216, 230, 0.5)'; // 浅蓝色半透明
        let globalPos = 0; // 全局位置指针
       
        let lineSpacing=15;
        cellsCtx.fillStyle = highlightColor; // 设置高亮颜色

        linesData.forEach(line => {
            const lineLength = line.text.length;
            const lineSelectionStart = Math.max(textData.cells_selectionStart - globalPos, 0);
            const lineSelectionEnd = Math.min(textData.cells_selectionEnd - globalPos, lineLength);

            if (lineSelectionStart < lineSelectionEnd) { // 有选中文本的行
                const lineMetrics = calculateLineMetrics(cellsCtx, line, lineSelectionStart, lineSelectionEnd);

                // 直接使用line.y进行定位，加上偏移量
                const startY = line.y  ;//- lineMetrics.maxHeight / 2; // 垂直居中调整

                // 绘制高亮区域，应用X方向偏移和调整后的Y方向偏移
                cellsCtx.fillRect(lineMetrics.startX , startY, lineMetrics.totalWidth, lineMetrics.maxHeight);
            }

            globalPos += lineLength;
        });
    }

    function calculateLineMetrics(cellsCtx, line, linecells_selectionStart, lineSelectionEnd) {
        let maxHeight = 0; // 选区内最大字体高度
        let startX = Number.MAX_VALUE; // 选区开始的X坐标
        let totalWidth = 0; // 累计宽度，用于计算宽度
        let accumulatedWidth = 0; // 累计宽度，用于计算startX

        line.styles.forEach(style => {
            cellsCtx.font = `${style.fontSize}px ${style.font}`; // 更新字体样式以进行测量
            const textPart = line.text.substring(Math.max(style.start, lineSelectionStart), Math.min(style.end, lineSelectionEnd));

            if (textPart.length > 0) {
                const metrics = cellsCtx.measureText(textPart);
                const textWidth = metrics.width;
                const textHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

                maxHeight = Math.max(maxHeight, textHeight); // 更新最大高度

                // 确定选区开始的X坐标
                if (style.start < lineSelectionStart) {
                    accumulatedWidth += cellsCtx.measureText(line.text.substring(style.start, lineSelectionStart)).width;
                } else if (startX === Number.MAX_VALUE) {
                    startX = accumulatedWidth; // 首次遇到重叠部分设置起始X坐标
                }

                totalWidth += textWidth; // 累加宽度
                accumulatedWidth += textWidth;
            } else {
                // 对于未选中的部分，累加宽度以确定后续选中部分的位置
                accumulatedWidth += cellsCtx.measureText(line.text.substring(style.start, style.end)).width;
            }
        });

        if (startX === Number.MAX_VALUE) {
            startX = 0; // 如果没有选中的文本，重置起始X坐标
        }

        return { startX, maxHeight, totalWidth };
    }

    function calculateTextWidth(text, fontSize, font) {
        // 实现具体的文本宽度计算逻辑
        // 可以使用cellsCanvas的measureText方法，这里需要传入cellsCtx和正确设置font
        cellsCtx.font = `${fontSize}px ${font}`;
        return cellsCtx.measureText(text).width;
    }


    function drawCursor(position) {
        if (position === null || position < 0 || position >= textData.text.length+1) return;
        var totalWidth=0;
        var chartCount=0;

        console.log("QQ2 drawCursor:",position);

        cells_charWidths.forEach(objectOfChar => {
            //console.log('QQ2 -> width: '+objectOfChar.width + ' x:' + objectOfChar.x);
            totalWidth+=objectOfChar.width;
            chartCount++;
        
        });
        if(position>chartCount)
        position=chartCount


        console.log("C2 开始绘制光标字体位置入参  :",position+" 字符个数: " + chartCount	);
        var cursorX = (cells_charWidths[position] ? cells_charWidths[position].x : 0) + 2; // 给光标一个小偏移
        const cursorHeight = 20; // 假定光标高度
        const cursorY = 100 - cursorHeight; // 基于文本绘制基线调整光标位置

        if(position>=chartCount)
        {
            cursorX=totalWidth;
            console.log("C2 : 光标位置超过字体宽度  :",position+"  字数:"+chartCount);
        }

        cellsCtx.beginPath();
        cellsCtx.moveTo(cursorX, cursorY);
        cellsCtx.lineTo(cursorX, cursorY + cursorHeight);
        cellsCtx.strokeStyle = 'black';
        cellsCtx.lineWidth = 2;
        cellsCtx.stroke();
    }
    
    // function drawCursor(position) {

       
    //     if (position === null || position.x < 0) return;

    //     let accumulatedHeight = 0; // 用于计算光标的Y坐标
    //     let cursorX = position.x; // 光标的X坐标
    //     let cursorY = position.y; // 光标的起始Y坐标
    //     let accumulatedLength = 0; // 累计字符长度，帮助定位光标所在行
    //     let lineFound = true; // 标记是否找到了光标所在行
    //     console.log("drawing cursor",position);
    //     for (let line of linesData) {
    //         const cells_lineHeight = line.height;
    //         if (position < accumulatedLength + line.text.length + 1 && !lineFound) {
    //             // 光标位于当前行
    //             cursorY = accumulatedHeight;
    //             let linePosition = position - accumulatedLength; // 光标在当前行的位置
    //             cursorX = linePosition === 0 ? 0 : getCursorXInLine(line, linePosition - 1);
    //             lineFound = true; // 标记找到光标所在行，避免进一步循环
    //         }
    //         accumulatedLength += line.text.length;
    //         if (!lineFound) {
    //             accumulatedHeight += cells_lineHeight;
    //         }
    //     }
	// 	console.log("QQ2: position.fontSize",position.fontSize);
    //     // 绘制光标
    //     if (lineFound) {
    //         cellsCtx.beginPath();
    //         cellsCtx.moveTo(cursorX, cursorY);
    //         cellsCtx.lineTo(cursorX, cursorY + parseInt(position.fontSize)); // 使用当前行的高度作为光标高度
    //         if(textData.cursorVisible)
    //         cellsCtx.strokeStyle = 'black';
    //     else
    //     cellsCtx.strokeStyle = 'transparent';
    //         cellsCtx.lineWidth = 1; // 可根据需要调整光标宽度
    //         cellsCtx.stroke();
    //     }
    // }


    function getCursorXInLine(line, position) {
        // 计算光标在行内的X坐标
        let cursorX = 0;
        for (let i = 0; i <= position; i++) {
            if (i < line.text.length) {
                const char = line.text[i];
                const charStyle = line.styles.find(s => i >= s.start && i < s.end) || { fontSize: 16, font: "Arial", color: "black" };
                cellsCtx.font = `${charStyle.fontSize}px ${charStyle.font}`;
                const metrics = cellsCtx.measureText(char);
                if (i === position) return cursorX + metrics.width; // 如果到达光标位置，返回当前累计宽度
                cursorX += metrics.width;
            }
        }
        return cursorX;
    }

    function clearSelection() {
            // 重置选择状态
            // textData.cells_selectionStart = null;
            // textData.cells_selectionEnd = null;

            //cells_isSelecting = false;
            // 如果需要在取消选择时也隐藏光标，取消以下注释
            // cells_cursorPosition = null;
            // cursorVisible = false; // 可选：同时隐藏光标

            // 重新渲染画布以更新显示状态
            renderText();
        }

    
    function blinkCursor() {
        textData.cursorVisible = !textData.cursorVisible;
           // console.log("blinking",textData.cursorVisible);
            renderText();
        }

       //setInterval(blinkCursor, 500); // 设置光标闪烁的间隔

        // 事件处理函数与之前相同，但需要更新以管理光标位置和可见性


    function getCharIndex(x) {
        for (let i = 0; i < cells_charWidths.length; i++) {
            const { width, x: charX } = cells_charWidths[i];
            if (x >= charX && x <= charX + width) {
                return i;
            }
        }
        return null;
    }
    //用坐标返回当前字符内容
    function getCharByIndex(position) {
        // 累计前面所有行的字符长度，以定位到正确的字符
      //  console.log("getCharByIndx:",position);
        let accumulatedLength = 0;
        for (let line of linesData) {
            if (position < accumulatedLength + line.text.length) {
                return line.text[position - accumulatedLength];
            }
            accumulatedLength += line.text.length;
        }
        return ''; // 如果索引超出范围，返回空字符串
    }


    function updateCursorPosition(x) {
        const rect = cellsCanvas.getBoundingClientRect();
        const clickX = x - rect.left; // 获取相对于cellsCanvas的点击位置
        cells_cursorPosition = getCharIndex(clickX);
        textData.cursorVisible = true; // 显示光标
    }

    function updateStylesForInsert(insertPosition, insertLength) {
        var isFind=false;
        return; //先不考虑样式的扩
       // console.log("C3 -> 更新样式！：",insertPosition);
        const selectedText = textData.text.substring(textData.cells_selectionStart, textData.cells_selectionEnd);
           //     console.log("C3 选中文字",selectedText); // Print the selected text to the console

        var tempIndex=0;
            textData.styles.forEach(style => {

              //  console.log("C1 -> forEach 更新样式！：",insertPosition," tempIndex:" ,tempIndex);
                tempIndex++;
                if(isFind==false)
                {
                    // 如果插入位置在当前样式范围之前，或恰好在其开始位置
                    if (insertPosition==0) 
                    {
                       
                        style.start =0;
                        style.end += insertLength;
                        isFind=true;
                    //    console.log("C1 ->",insertPosition," 在当前样式之前  style.start="+insertPosition);
                        //当字符输入完成之后insertPosition会自增 ，要注意这个现象 。。
                    }
                    else
                    {  //插入位置在当前样式范围之间结束位置+1
                        if (insertPosition> style.start&&insertPosition <style.end)  
                        {
                       //     console.log("C1 -> ",insertPosition," 在当前样式之间");
                            style.end += insertLength;
                            isFind=true;
                        }else
                        {
                            if(insertPosition===style.end)
                            {
                            //    console.log("C1 ->",insertPosition," 在当前样式最后尾");
                                style.end += insertLength;
                                isFind=true;
                            }

                        }

                       
                    }
                  
                    

                }                    
                 else {
                    // 如果插入位置在当前样式范围内部，只需要调整结束位置
                    style.start += insertLength;
                    style.end += insertLength;
                }
                
            });
        }

function renderSelection() {
// 遍历每个字符，只有当字符索引在cells_selectionStart和cells_selectionEnd之间时才渲染高亮背景
    for (let i = textData.cells_selectionStart; i < textData.cells_selectionEnd; i++) {
        // 假设 getCharPosition 返回字符的位置和宽度
        let { x, y, width } = getCharPosition(i);
        // 绘制选区高亮背景
        cellsCtx.fillStyle = 'rgba(173, 216, 230, 0.5)'; // 高亮颜色，可自定义
        cellsCtx.fillRect(x, y - charHeight, width, charHeight); // 假设 charHeight 是字符的高度
    }
}
function compressStyles() {
    compressEachStyleProperty(textData.fontStyles, 'font');
    compressEachStyleProperty(textData.fontSize, 'fontSize');
    compressEachStyleProperty(textData.fontColor, 'color');
    compressEachStyleProperty(textData.italic, 'italic');
    compressEachStyleProperty(textData.bold, 'bold');
    compressEachStyleProperty(textData.underline, 'underline');
    compressEachStyleProperty(textData.underlineStyle, 'style');
    compressEachStyleProperty(textData.underlineColor, 'underlineColor');
    compressEachStyleProperty(textData.background, 'background');
    
}

function compressEachStyleProperty(styleArray, property) {
    if(styleArray==null)
    return;
    if (styleArray.length === 0) return;

    // 首先，根据样式段的开始位置进行排序，确保样式按顺序处理
    styleArray.sort((a, b) => a.start - b.start);

    let compressedStyles = [styleArray[0]];

    for (let i = 1; i < styleArray.length; i++) {
        let lastStyle = compressedStyles[compressedStyles.length - 1];
        let currentStyle = styleArray[i];

        // 检查当前样式是否与上一个样式相同，并且连续
        if (lastStyle[property] === currentStyle[property] && lastStyle.end === currentStyle.start) {
            // 如果当前样式与上一个样式在属性上相同且连续，则合并这两个样式段
            lastStyle.end = currentStyle.end;
        } else {
            compressedStyles.push(currentStyle);
        }
    }

    // 更新原样式数组为压缩后的样式数组
    styleArray.splice(0, styleArray.length, ...compressedStyles);
}
function updateSelectedTextSize(newFontSize) {
    // 更新fontSize数组
    updateStyleProperty(textData.fontSize, newFontSize, "fontSize");
    updateLinesDataStyles();
    renderText();
}
function updateSelectedTextColor(newColor) {
    updateStyleProperty(textData.fontColor, newColor, 'color');
}

           
function updateStyleProperty(styleArray, newValue, property) {
    let newStyles = [];
    let hasOverlap = false; // 标记选区内的样式是否与现有样式有重叠

    // 检查并更新现有样式
    styleArray.forEach(style => {
        if (style.end <= textData.cells_selectionStart || style.start >= textData.cells_selectionEnd) {
            // 完全不在选区内的样式直接保留
            newStyles.push(style);
        } else {
            hasOverlap = true; // 选区内至少有一部分样式与现有样式重叠

            // 部分或完全在选区内的样式需要细分和更新
            if (style.start < textData.cells_selectionStart) {
                // 选区前的样式分割出来
                newStyles.push({
                    ...style,
                    end: textData.cells_selectionStart,
                });
            }

            // 更新选区内的样式
            newStyles.push({
                start: Math.max(style.start, textData.cells_selectionStart),
                end: Math.min(style.end, textData.cells_selectionEnd),
                [property]: newValue,
            });

            if (style.end > textData.cells_selectionEnd) {
                // 选区后的样式分割出来
                newStyles.push({
                    ...style,
                    start: textData.cells_selectionEnd,
                });
            }
        }
    });

    // 如果选区内原本没有完全匹配的样式，则为选区创建新的样式段
    if (!hasOverlap) {
        newStyles.push({start: textData.cells_selectionStart, end: textData.cells_selectionEnd, [property]: newValue});
    } else {
        // 确保覆盖整个选区
        ensureFullCoverage(newStyles, textData.cells_selectionStart, textData.cells_selectionEnd, newValue, property);
    }

    // 用新的样式数组替换旧的
    styleArray.splice(0, styleArray.length, ...newStyles);
}


function ensureFullCoverage(styles, start, end, value, property) {
    // 查找选区起点和终点之间是否存在未覆盖的区域
    let covered = new Array(end - start).fill(false);

    styles.forEach(style => {
        if (style[property] === value) {
            for (let i = Math.max(style.start, start); i < Math.min(style.end, end); i++) {
                covered[i - start] = true;
            }
        }
    });

// 填充未覆盖的区域
for (let i = 0; i < covered.length; i++) {
        if (!covered[i]) { // 发现未覆盖区域
            let newStart = i + start;
            let newEnd = newStart + 1;

            // 扩展这个未覆盖区域到其最大长度
            while (newEnd < end && !covered[newEnd - start]) {
                newEnd++;
            }

            // 添加新的样式段以覆盖这个区域
            styles.push({start: newStart, end: newEnd, [property]: value});

            // 更新覆盖数组
            for (let j = newStart; j < newEnd; j++) {
                covered[j - start] = true;
            }

            i = newEnd - start - 1; // 跳过已处理区域
        }
    }
}

function mergeStyles(styles) {
    // 此函数用于合并同一行中相邻且样式相同的样式块
    // 注意：这里的实现取决于具体需求，可能需要根据实际情况调整
    return styles.sort((a, b) => a.start - b.start); // 简单示例：按开始位置排序
}

function findLineIndexForPosition(position) {
    // 返回给定位置的行索引
    for (let i = 0; i < linesData.length; i++) {
        if (linesData[i].start <= position && position <= linesData[i].end) {
            return i;
        }
    }
    return -1; // 如果位置不在任何行中，则返回-1
}


function updateSelectedFont(newFont) {
    updateStyleProperty(textData.fontStyles, newFont, 'font');
}

function updateSelectedItalic(isItalic) {
    updateStyleProperty(textData.italic, isItalic, "italic");
}

function updateSelectedUnderLine(hasUnderline) {
    updateStyleProperty(textData.underline, hasUnderline, "underline");
}


function updateSelectedUnderLineStyle(underLineStyle) {
    updateStyleProperty(textData.underlineStyle, underLineStyle, "style");
}


function updateSelectedUnderLineColor(underlineColor) {
    console.log("C4 underlineColor: " + underlineColor," textData.underlineColor: " + textData.underlineColor);

    updateStyleProperty(textData.underlineColor, underlineColor, "color");
    
}

function updateSelectedLineSpacing(lineSpacing) {
    textData.lineSpacing=lineSpacing;
}



function updateSelectedFirstLineIndent(Indent) {
    textData.firstLineIndent=Indent;
}


function updateHorizontalAlign(alignment) {
    textData.horizontalAlign=alignment;
}

function updateVerticalAlign(alignment) {
    textData.verticalAlign=alignment;
}

function updateSelectedBold(isBold) {
    updateStyleProperty(textData.bold, isBold, "bold");
}

function updateSelectedGBColor(color) {
    updateStyleProperty(textData.background, color, "background");
}


    
function updateLinesDataStyles() {         
    generateLinesData();          
    updateTextLayout(); // 假设这个函数处理文档布局的其他更新
}

function updateTextLayout() {
let currentY = 0; // 假设文档的起始Y坐标为0
linesData.forEach(line => {               
    line.y = currentY;
    currentY += line.height; // 更新下一行的起始Y坐标
});
// 更新整个文档的高度
textData.totalHeight = currentY;
}

